Powershell Runspace - How do you properly handle read/write to the threads? - multithreading

Everything I read online about this only shows how to send information to the UI which works for me now due to the comment suggestion.
I am unable to find a way to do the reverse and send to an output while running a thread.
The end goal is to use a WPF multithread with being able to interact with selenium running the background. grabbing and sending information to websites while still actively being able to use the WPF.
I can do this in C# but the current job wants this all to be in PowerShell and this seems to be on the right track to do this.
If I am wrong please guide me to the correct way to do something like this then.
Code:
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase
Function Create-WPFWindow {
Param($Hash)
# Create a window object
$Window = New-Object System.Windows.Window
$Window.Width = '600'
$Window.Height = '300'
$Window.Title = 'WPF-CONTROL'
$window.WindowStartupLocation = [System.Windows.WindowStartupLocation]::CenterScreen
$Window.ResizeMode = [System.Windows.ResizeMode]::NoResize
# Create a Label object
$Label = New-Object System.Windows.Controls.Label
$Label.Height = 40
$Label.HorizontalContentAlignment = 'Left'
$Label.VerticalContentAlignment = 'Center'
$Label.FontSize = 15
$Label.Content = 'Activate:'
$Hash.Label = $Label
# Create a TextBlock object
$TextBlock = New-Object System.Windows.Controls.TextBlock
$TextBlock.Height = 150
$TextBlock.FontSize = 20
$TextBlock.TextWrapping = 'Wrap'
$TextBlock.Text = "Test"
$Hash.TextBlock = $TextBlock
# Create a Button1 object
$Button1 = New-Object System.Windows.Controls.Button
$Button1.Width = 300
$Button1.Height = 35
$Button1.HorizontalContentAlignment = 'Center'
$Button1.VerticalContentAlignment = 'Center'
$Button1.FontSize = 20
$Button1.Content = 'Start'
$Hash.Button1 = $Button1
# Assemble the window
$StackPanel1 = New-Object System.Windows.Controls.StackPanel
$StackPanel1.Margin = '150,20,5,5'
$StackPanel1.Orientation = 'Horizontal'
$StackPanel1.Children.Add($Button1)
$StackPanel2 = New-Object System.Windows.Controls.StackPanel
$StackPanel2.Margin = '5,5,5,5'
$StackPanel2.Orientation = 'Vertical'
$StackPanel2.Children.Add($Label)
$StackPanel2.Children.Add($TextBlock)
$StackPanel = New-Object System.Windows.Controls.StackPanel
$StackPanel.Margin = '5,5,5,5'
$StackPanel.Children.Add($StackPanel1)
$StackPanel.Children.Add($StackPanel2)
$Window.Content = $StackPanel
# Stop the service and release the resources
$Window.Add_Closing({
$Hash.On = $false
$global:p.BeginInvoke()
$global:p.Dispose()})
$Hash.Window = $Window
}
$Hash = [hashtable]::Synchronized(#{})
# Create a WPF window and add it to a Hash table
Create-WPFWindow $Hash | Out-Null
$Hash.Button1.Add_Click({
if ($Hash.On -eq $true){
$p.Stop()
$Hash.On = $false
$Hash.Button1.Background = 'Green'
$Hash.Button1.Content = 'Start'
}else{
$Hash.On = $true
$Hash.Button1.Background = 'Red'
$Hash.Button1.Content = 'Stop'
}
$p.BeginInvoke() | Out-Null
})
$rs_dForm = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
$rs_dForm.ApartmentState = 'STA'
$rs_dForm.ThreadOptions = 'ReuseThread'
$rs_dForm.Open()
$rs_dForm.SessionStateProxy.SetVariable('Hash', $Hash)
$p = [PowerShell]::Create().AddScript({
Function global:FileEventListener (){
if ($Hash.On){
for ($i = 0; $i -lt 10; $i++) {
$Hash.Window.Dispatcher.Invoke([action]{$Hash.TextBlock.Text = "Test: " + $i.ToString()})
#$Hash.TextBlock.Text = "Test: " + $i.ToString() #<----not updating?
Write-Output "Test: " + $i.ToString() #<----not possible?
Start-Sleep -Seconds 1
}
}
}
FileEventListener
})
$p.Runspace = $rs_dForm
# Show the window
$Hash.Window.ShowDialog() | Out-Null

Related

Why am I receiving a Connect-AzureAD error after connecting to the service?

I am working on my first GUI in Powershell. I have used small scripts with the Azure modules in the past so I am even more confused as to why this is breaking. In the script below there are two places that I tried to import and use the connect-azuread cmdlet so it is commented in the second spot but I attempted it in both places. The script is meant to present a GUI to select a csv of UPNs to find additional info in the azure tenant and return it in another csv. No matter where I place the connect-azuread command, I recieve the error: "You must call the Connect-AzureAD cmdlet before calling any other cmdlets." When I run the script it does prompt me to sign into Azure with the standard Microsoft login page but it apparently does not hold onto the credential.
This is the code that I tried:
Install-Module AzureAD -Force | Out-Null
Import-Module AzureAD | Out-Null
Connect-AzureAD
Add-Type -AssemblyName System.Windows.Forms
$LocationForm = New-Object system.Windows.Forms.Form
$LocationForm.ClientSize = '500,300'
$LocationForm.text = "Azure Information Pull"
$LocationForm.BackColor ='#ffffff'
$Title = New-Object System.Windows.Forms.Label
$Title.text = "Retrieving Data From Azure Tenant"
$Title.AutoSize = $true
$Title.Location = New-Object System.Drawing.Point(20,20)
$Title.Font = 'Microsoft Sans Serif,13'
$Description = New-Object System.Windows.Forms.Label
$Description.Text = "Retrieve UPN, Display Name, Email, and EmployeeID from Azure Tenant."
$Description.AutoSize = $False
$Description.Width = 450
$Description.Height = 50
$Description.location = New-Object System.Drawing.Point(20,50)
$Description.Font = 'Microsoft Sans Serif,10'
#$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog
#$FileBrowser.Title = "Select a file"
#$FileBrowser.InitialDirectory = [Environment]::GetFolderPath('Desktop')
#$FileBrowser.Filter = "CSV (*.csv)| *.csv"
#$SelectedFile = $FileBrowser.FileName
Function Get-FileName()
{
[System.Reflection.Assembly]::LoadWithPartialName(“System.windows.forms”) |
Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = [Environment]::GetFolderPath('Desktop')
$OpenFileDialog.filter = "CSV (*.csv)| *.csv"
$OpenFileDialog.ShowDialog() | Out-Null
$global:Input = $OpenFileDialog.filename
$Input
} #end function Get-FileName
$InputFileBtn = New-Object System.Windows.Forms.Button
$InputFileBtn.BackColor = '#a4ba67'
$InputFileBtn.Text = "Select File"
$InputFileBtn.Width = 90
$InputFileBtn.height = 30
$InputFileBtn.Location = New-Object System.Drawing.Point(370,250)
$InputFileBtn.Font = 'Microsoft Sans Serif,10'
$InputFileBtn.ForeColor = "#ffffff"
$InputFileBtn.Add_Click({Get-FileName})
$cancelBtn = New-Object system.Windows.Forms.Button
$cancelBtn.BackColor = "#ffffff"
$cancelBtn.text = "Finish"
$cancelBtn.width = 90
$cancelBtn.height = 30
$cancelBtn.location = New-Object System.Drawing.Point(260,250)
$cancelBtn.Font = 'Microsoft Sans Serif,10'
$cancelBtn.ForeColor = "#000"
$cancelBtn.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$LocationForm.CancelButton = $cancelBtn
$LocationForm.Controls.AddRange(#($Title,$Description,$cancelBtn,$InputFileBtn))
[void]$LocationForm.ShowDialog()
#Begin Script
#Install-Module AzureAD -Force | Out-Null
#Import-Module AzureAD | Out-Null
#Connect-AzureAD
$OutputLocation = Split-Path -Path $global:Input
$UserList = import-csv -path $global:Input
foreach($user in $UserList){
Get-AzureADUser -ObjectID $user.upn | select UserPrincipalName,Displayname,mail, #{Name = 'EmployeeId'; Expression = {$_.ExtensionProperty.employeeId}} | export-csv "$OutputLocation\output.csv" -append -noTypeInformation}
I do not expect to get the error to connect to the azure ad module when I have already made the connection.
I tried to reproduce the same in my environment and got the results successfully like below:
Connect-AzureAD
Add-Type -AssemblyName System.Windows.Forms
$LocationForm = New-Object system.Windows.Forms.Form
$LocationForm.ClientSize = '500,300'
$LocationForm.text = "Azure Information Pull"
$LocationForm.BackColor ='#ffffff'
$Title = New-Object System.Windows.Forms.Label
$Title.text = "Retrieving Data From Azure Tenant"
$Title.AutoSize = $true
$Title.Location = New-Object System.Drawing.Point(20,20)
$Title.Font = 'Microsoft Sans Serif,13'
$Description = New-Object System.Windows.Forms.Label
$Description.Text = "Retrieve UPN, Display Name, Email, and EmployeeID from Azure Tenant."
$Description.AutoSize = $False
$Description.Width = 450
$Description.Height = 50
$Description.location = New-Object System.Drawing.Point(20,50)
$Description.Font = 'Microsoft Sans Serif,10'
[Environment]::GetFolderPath('Desktop')
Function Get-FileName()
{
[System.Reflection.Assembly]::LoadWithPartialName(“System.windows.forms”) |
Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = [Environment]::GetFolderPath('Desktop')
$OpenFileDialog.filter = "CSV (*.csv)| *.csv"
$OpenFileDialog.ShowDialog() | Out-Null
$global:Input = $OpenFileDialog.filename
$Input
}
$InputFileBtn = New-Object System.Windows.Forms.Button
$InputFileBtn.BackColor = '#a4ba67'
$InputFileBtn.Text = "Select File"
$InputFileBtn.Width = 90
$InputFileBtn.height = 30
$InputFileBtn.Location = New-Object System.Drawing.Point(370,250)
$InputFileBtn.Font = 'Microsoft Sans Serif,10'
$InputFileBtn.ForeColor = "#ffffff"
$InputFileBtn.Add_Click({Get-FileName})
$cancelBtn = New-Object system.Windows.Forms.Button
$cancelBtn.BackColor = "#ffffff"
$cancelBtn.text = "Finish"
$cancelBtn.width = 90
$cancelBtn.height = 30
$cancelBtn.location = New-Object System.Drawing.Point(260,250)
$cancelBtn.Font = 'Microsoft Sans Serif,10'
$cancelBtn.ForeColor = "#000"
$cancelBtn.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$LocationForm.CancelButton = $cancelBtn
$LocationForm.Controls.AddRange(#($Title,$Description,$cancelBtn,$InputFileBtn))
[void]$LocationForm.ShowDialog()
$OutputLocation = Split-Path -Path $global:Input
$UserList = import-csv -path $global:Input
foreach($user in $UserList){
Get-AzureADUser -ObjectID $user.upn | select UserPrincipalName,Displayname,mail, #{Name = 'EmployeeId'; Expression = {$_.ExtensionProperty.employeeId}} | export-csv "$OutputLocation\output1.csv" -append -noTypeInformation}
The output file is exported successfully as below:
The error "You must call the Connect-AzureAD cmdlet before calling any other cmdlets" usually occurs if connection to the Azure AD Account is not successful.
Try Connect-AzureAD by using below command:
$credentials = Get-Credential
Connect-AzureAD -Credential $credentials
Otherwise, try to Connect Azure AD like below:
Connect-AzureAd -TenantId TenantID
If still the issue persists, try re-install the AzureAD module:
Uninstall-Module AzureAD
Install-Module AzureAD
Import-Module AzureAD

Executing excel formula using powershell taking too much time

I am having below code which I using to calculate
$excel = new-object -comobject Excel.Application
$excel.visible = $false
$workbook = $excel.workbooks.open("C:\SLAFile.xlsx")
$worksheet = $workbook.Worksheets.Item(1)
$rows = $worksheet.range("D2").currentregion.rows.count
$STDSheet = $workbook.WorkSheets.Add()
$STDSheet.Name = 'STD'
###### Copy Date #####
$worksheet.activate()
$lastRow1 = $worksheet.UsedRange.rows.count
$range1 = $worksheet.Range("B2:B$lastRow1")
$range1.copy()
$STDSheet.activate()
$lastRow2 = $STDSheet.UsedRange.rows.count + 1
$range2 = $STDSheet.Range("A$($lastRow2)")
$STDSheet.Paste($range2)
###### Copy Date ######
###### Copy SYMM_ID ####
$worksheet.activate()
$lastRow3 = $worksheet.UsedRange.rows.count
$range3 = $worksheet.Range("A2:A$lastRow3")
$range3.copy()
$STDSheet.activate()
$lastRow4 = $STDSheet.UsedRange.rows.count + 1
$range4 = $STDSheet.Range("C$($lastRow2)")
$STDSheet.Paste($range4)
###### Copy SYMM_ID ####
####### STD Column Header #######
$STDSheet.Cells(1,1) = 'Time (DD.MM.YYYY HH:MM:SS)'
$STDSheet.Cells(1,2) = 'DATE (TEXT FORMAT)'
$STDSheet.Cells(1,3) = 'SYMM_ID'
$STDSheet.Cells(1,4) = 'STD_RT'
$STDSheet.Cells(1,5) = 'IO/sec'
$STDSheet.Cells(1,6) = 'DATA/sec'
$STDSheet.Cells(1,7) = 'Block Size'
$STDSheet.Cells(1,8) = 'MIN RT/6h'
####### STD Column Header #######
##### STD Report Part ####
$count=73
for($j=2;$j -le $rows;$j++)
{
$k = $j-1
$STDSheet.range("B$j:B$j").formula = '=TEXT(A'+$j+',"dd-mm-yyyy hh:mm")'
$STDSheet.range("E$j:E$j").formula = '=IFERROR(SUMIFS(SLA!$G:$G,SLA!$C:$C,"SG_STG_*_L_*STD",SLA!$B:$B,$B'+$j+',SLA!$D:$D,"<>0"),0)+IFERROR(SUMIFS(SLA!$H:$H,SLA!$C:$C,"SG_STG_*_L_*STD",SLA!$B:$B,$B'+$j+',SLA!$D:$D,"<>0"),0)'
$STDSheet.range("D$j:D$j").formula = '=IFERROR(AVERAGEIFS(SLA!$D:$D,SLA!$C:$C,"SG_STG_*_L_*STD",SLA!$B:$B,SLA!B'+$j+',SLA!$D:$D,"<>0"),"-")'
$STDSheet.range("F$j:F$j").formula = '=IFERROR(SUMIFS(SLA!$E:$E,SLA!$C:$C,"SG_STG_*_L_*STD",SLA!$B:$B,$B'+$j+',SLA!$D:$D,"<>0"),0)+IFERROR(SUMIFS(SLA!$F:$F,SLA!$C:$C,"SG_STG_*_L_*STD",SLA!$B:$B,$B'+$j+',SLA!$D:$D,"<>0"),0)'
$STDSheet.range("G$j:G$j").formula = '=IFERROR($F'+$j+'*1024/$E'+$j+',"-")'
$STDSheet.range("H$j:H$j").formula = '=IF(COUNTIF($D'+$j+':$D'+$count+',">0")=72,MIN($D'+$j+':$D'+$count+'),"-")'
$STDSheet.range("I1:I1").formula = '="Nb Period with Min RT > "&5&"ms"'
$STDSheet.range("I$j:I$j").formula = '=IFS($H'+$j+'="-","NA",$H'+$j+'<=5,"OK",$H'+$k+'>5,"NOK CONT",1,"NOK START")'
$STDSheet.range("j1:j1").formula = '=COUNTIF($I:$I,"NOK START")'
The problem is, when I keep only 1000-2000 records in the input file, the code executes very quickly.
But the actual input file contains around 90k records. when I execute that it takes too much time.
Please let me know is there anything wrong with the code? Is there any way to make the execution faster?
While trying I have broke the master excel into 1000 rows each and kept in separate files and tried to execute. but then also I am getting the same slowness issue
$GetExcels = Get-ChildItem -Path 'C:\xlfile\multiple'
foreach($EFile in $GetExcels)
{
}

For loop within For loop PowerShell and Excel not working

I am basically trying to compare a cell within Excel against another cell within another worksheet using PowerShell. This is the code I am using:
# Define location
$crs = "C:\temp\CRSENGCY_PS.xlsx"
$english = "English"
$welsh = "Welsh"
$SubSection = "SubSection"
# Create instance
$objExcel = New-Object -ComObject Excel.Application
$workBook = $objExcel.Workbooks.Open($crs)
$englishSheet = $workBook.Worksheets.Item($english)
$subSectionSheet = $workBook.Worksheets.Item($SubSection)
$objExcel.Visible = $false
# Num of rows
$engRowMax = 1812
$subRowMax = 677
# Define columns
$rowName, $colName = 1, 1
for ($i=1; $i -le $subRowMax; $i++) {
$SubSectionName = $subSectionSheet.Cells.Item($rowName+$i,2).Text
$3SubSections = $SubSectionName.Substring(0, 3)
for ($i=1; $i -le $engRowMax; $i++) {
$englishName = $englishSheet.Cells.Item($rowName+$i, $colName).Text
$3englishName = $englishName.Substring(0, 3)
if ($3englishName -eq $3SubSections) {
Write-Host("Success")
} else {
Write-Host("Failed" + $3SubSections + " " + $3englishName)
}
}
}
$objExcel.Quit()
The issue I have is that the for loop at the bottom only runs once. The for loop inside runs the correct number of times. If I remove the nested for loop it works fine.
I believe your problem is that the nested For loop doesn't end. You will probably want to put a Break statement in both For loops to tell them at what point you want them to exit the loops.
The following links may help explain more about a Break statement:
PowerShell Looping: Basics of the Break
Nested ForEach() in PowerShell
If anyone is interested here is my working script -
# Define location
$crs = "C:\temp\CRSENGCY_PS.xlsx"
$english = "English"
$welsh = "Welsh"
$SubSection = "SubSection"
# Create instance
$objExcel = New-Object -ComObject Excel.Application
$workBook = $objExcel.Workbooks.Open($crs)
$englishSheet = $workBook.Worksheets.Item($english)
$welshSheet = $workBook.Worksheets.Item($welsh)
$subSectionSheet = $workBook.Worksheets.Item($SubSection)
$objExcel.Visible=$false
# Num of rows
$engRowMax = 1812
$subRowMax = 677
# Define columns
$rowName,$colName = 2,1
# Vars
$engSubID = $englishSheet.Cells.Item($rowName+$s,8)
$welSubID = $welshSheet.Cells.Item($rowName+$s,8)
for ($i=0; $i -le 339; $i++)
{
$SubSectionName = $subSectionSheet.Cells.Item($rowName+$i,2).text
$SubSecID = $subSectionSheet.Cells.Item($rowName+$i,1).text
#$3SubSections = $SubSectionName.Substring(0,3)
$SubSecRef = $SubSectionName.Substring(0, $SubSectionName.IndexOf(' '))
#Write-Host($SubSecRef)
for ($s=1; $s -le 1811; $s++)
{
$englishName = $englishSheet.Cells.Item($rowName+$s,$colName).text
#$3englishName = $englishName.Substring(0,$englishName.)
$refno = $englishName.Substring(0, $englishName.IndexOf('.') + 1 + $englishName.Substring($englishName.IndexOf('.') + 1).IndexOf('.'))
if ($SubSecRef -eq $refno)
{
$englishSheet.Cells.Item($rowName+$s,8) = $SubSecID
Write-host("Match!!")
}
else
{
#Write-host("No Match " + $3SubSections + " " + $3englishName)
}
}
Write-Host($i)
}
$workBook.Save()
$workBook.Close()
$objExcel.Quit()

Powershell Excel Graph PlotBy Column Instead of Row

Thank you all in advanced.
I am trying to create a Script that will gather information from a customer environment and will then create Excel Workbooks and Sheets for each component. what i am stuck in at the moment is the graph in the excel.
This graph will draw the graph of the CPU and Memory Utilization for the NSX Manager (Which is a linux machine at the end) from the data populated into the excel sheet already. so the script will add the info of the CPU and Memory utilization over time on the Excel sheet and then draw the graph from the data added.
Tha issue is that the graph plot is based on the row and i want it to change into column.
So the output of the script at the moment give me the following:
Wrong Ploting
And it should be as follow: Correct Ploting
PS: the Correct one was done by a normal Powershell graphing.
I know that thier is a method called Chart.PlotBy = xlColumns however i can not find the exact sintax to write it as all the available example over google is for VBA.
Code is as follow:
#Create the title of 12th section in the Work Book Sheet for the NSX Manager Resource Usage Historic Info.
$NsxManagerWorkSheet.Cells.Item(70,4)= 'NSX Manager Resource Usage Historic Info'
$NsxManagerWorkSheet.Cells.Item(70,4).Font.Size = 14
$NsxManagerWorkSheet.Cells.Item(70,4).Font.Bold=$True
$NsxManagerWorkSheet.Cells.Item(70,4).Font.Name = "Calibri"
$NsxManagerWorkSheet.Cells.Item(70,4).Font.ColorIndex = 2
$NsxManagerWorkSheet.Cells.Item(70,4).Interior.ColorIndex = 9
$Range = $NsxManagerWorkSheet.Range("D70","F70")
$Range.Merge() | Out-Null
$Range.HorizontalAlignment = -4108
$Range.verticalalignment = -4108
$Range.BorderAround(1,2,48)
#Create Categories of this Sections.
$NsxManagerWorkSheet.Cells.Item(71,4)= "Time Stamp"
$NsxManagerWorkSheet.Cells.Item(71,4).Font.Size = 12
$NsxManagerWorkSheet.Cells.Item(71,4).Font.Bold=$True
$NsxManagerWorkSheet.Cells.Item(71,4).Font.Name = "Calibri"
$NsxManagerWorkSheet.Cells.Item(71,4).Font.ColorIndex = 2
$NsxManagerWorkSheet.Cells.Item(71,4).Interior.ColorIndex = 16
$NsxManagerWorkSheet.Cells.Item(71,5)= "CPU"
$NsxManagerWorkSheet.Cells.Item(71,5).Font.Size = 12
$NsxManagerWorkSheet.Cells.Item(71,5).Font.Bold=$True
$NsxManagerWorkSheet.Cells.Item(71,5).Font.Name = "Calibri"
$NsxManagerWorkSheet.Cells.Item(71,5).Font.ColorIndex = 2
$NsxManagerWorkSheet.Cells.Item(71,5).Interior.ColorIndex = 16
$NsxManagerWorkSheet.Cells.Item(71,6)= "Memory"
$NsxManagerWorkSheet.Cells.Item(71,6).Font.Size = 12
$NsxManagerWorkSheet.Cells.Item(71,6).Font.Bold=$True
$NsxManagerWorkSheet.Cells.Item(71,6).Font.Name = "Calibri"
$NsxManagerWorkSheet.Cells.Item(71,6).Font.ColorIndex = 2
$NsxManagerWorkSheet.Cells.Item(71,6).Interior.ColorIndex = 16
$Range = $NsxManagerWorkSheet.Range("D71")
$Range.HorizontalAlignment = -4108
$Range.verticalalignment = -4108
$Range.BorderAround(1,2,48)
$Range = $NsxManagerWorkSheet.Range("E71")
$Range.HorizontalAlignment = -4108
$Range.verticalalignment = -4108
$Range.BorderAround(1,2,48)
$Range = $NsxManagerWorkSheet.Range("F71")
$Range.HorizontalAlignment = -4108
$Range.verticalalignment = -4108
$Range.BorderAround(1,2,48)
#Create the Content Values of 12th section in the Work Book Sheet for the NSX Manager Resource Usage Historic Info.
$ReqRow = 72
Foreach ($Line in $NsxCpuHistoricUsage) {
$Output = $Line.Timestamp
$NsxManagerWorkSheet.Cells.Item($ReqRow,4)= "$Output"
$Output = $Line.Value
$NsxManagerWorkSheet.Cells.Item($ReqRow,5)= "$Output"
$OutPut = ($NsxMemoryHistoricUsage | Where-Object {$_.Timestamp -Match $Line.Timestamp}).Value
$NsxManagerWorkSheet.Cells.Item($ReqRow,6)= "$Output"
$ReqRow++
}
$start1 = $NsxManagerWorkSheet.range("D72")
$EndOfCell1 = $NsxManagerWorkSheet.Range($start1,$start1.End($xlDirection::xlDown))
$Range = $NsxManagerWorkSheet.Range("D72:D$($EndOfCell1.item($EndOfCell1.count).Row)")
$Range.Font.Size = 12
$Range.Font.Bold=$True
$Range.HorizontalAlignment = -4108
$Range.verticalalignment = -4108
$Range.BorderAround(1,2,1)
$start2 = $NsxManagerWorkSheet.range("E72")
$EndOfCell2 = $NsxManagerWorkSheet.Range($start2,$start2.End($xlDirection::xlDown))
$Range = $NsxManagerWorkSheet.Range("E72:E$($EndOfCell2.item($EndOfCell2.count).Row)")
$Range.Font.Size = 12
$Range.Font.Bold=$False
$Range.HorizontalAlignment = -4108
$Range.verticalalignment = -4108
$Range.BorderAround(1,2,1)
$start3 = $NsxManagerWorkSheet.range("F72")
$EndOfCell3 = $NsxManagerWorkSheet.Range($start3,$start3.End($xlDirection::xlDown))
$Range = $NsxManagerWorkSheet.Range("F72:F$($EndOfCell3.item($EndOfCell3.count).Row)")
$Range.Font.Size = 12
$Range.Font.Bold=$False
$Range.HorizontalAlignment = -4108
$Range.verticalalignment = -4108
$Range.BorderAround(1,2,1)
#----------------------------------------------------
#Create Chart for NSX Manager Resource Historic Utilization
$NsxManagerResourcesHistoricChart = $NsxManagerWorkSheet.Shapes.AddChart().Chart
$NsxManagerResourcesHistoricChart.ChartType = $xlChart::xlLine
$NsxManagerResourcesHistoricChart.HasTitle = $True
$NsxManagerResourcesHistoricChart.HasLegend = $True
$NsxManagerResourcesHistoricChart.ChartTitle.Text = "NSX Manager Resource Historic Utilization"
$xaxis = $NsxManagerResourcesHistoricChart.Axes($xlAxes::XlCategory)
$xaxis.HasTitle = $True
$xaxis.AxisTitle.Text = "Time"
$yaxis = $NsxManagerResourcesHistoricChart.Axes($xlAxes::XlValue)
$yaxis.HasTitle = $True
$yaxis.AxisTitle.Text = "Utilization Percentage (%)"
$start1 = $NsxManagerWorkSheet.range("D71")
$Y1 = $NsxManagerWorkSheet.Range($start1,$start1.End($xlDirection::xlDown))
$start1 = $NsxManagerWorkSheet.range("F71")
$X1 = $NsxManagerWorkSheet.Range($start1,$start1.End($xlDirection::xlDown))
$chartdata1=$NsxManagerWorkSheet.Range("D$($Y1.item(1).Row):D$($Y1.item($Y1.count).Row),F$($X1.item(1).Row):F$($X1.item($X1.count).Row)")
$NsxManagerResourcesHistoricChart.SetSourceData($chartdata1)
$RangeToCover = $NsxManagerWorkSheet.Range("D47:F67")
$ChartObj = $NsxManagerResourcesHistoricChart.Parent
$ChartObj.Top = $RangeToCover.Top
$ChartObj.Left = $RangeToCover.Left
$ChartObj.Height = $RangeToCover.Height
$ChartObj.Width = $RangeToCover.Width
#----------------------------------------------------
Any help would be much apritiated
Thank you.
Was able to get it working by adding the below:
$xlPlotBy = [Microsoft.Office.Interop.Excel.XlRowCol]
$NsxManagerResourcesHistoricChart.PlotBy = $xlPlotBy::xlColumns
$NsxManagerResourcesHistoricChart = $NsxManagerWorkSheet.Shapes.AddChart().Chart
$NsxManagerResourcesHistoricChart.ChartType = $xlChart::xlLine
$NsxManagerResourcesHistoricChart.PlotBy = $xlPlotBy::xlColumns
$NsxManagerResourcesHistoricChart.HasTitle = $True
$NsxManagerResourcesHistoricChart.HasLegend = $True
$NsxManagerResourcesHistoricChart.ChartTitle.Text = "NSX Manager Resource Historic Utilization"
$xaxis = $NsxManagerResourcesHistoricChart.Axes($xlAxes::XlCategory)
$xaxis.HasTitle = $True
$xaxis.AxisTitle.Text = "Time"
$yaxis = $NsxManagerResourcesHistoricChart.Axes($xlAxes::XlValue)
$yaxis.HasTitle = $True
$yaxis.AxisTitle.Text = "Utilization Percentage (%)"
$start1 = $NsxManagerWorkSheet.range("D71")
$Y1 = $NsxManagerWorkSheet.Range($start1,$start1.End($xlDirection::xlDown))
$start1 = $NsxManagerWorkSheet.range("F71")
$X1 = $NsxManagerWorkSheet.Range($start1,$start1.End($xlDirection::xlDown))
$chartdata1=$NsxManagerWorkSheet.Range("D$($Y1.item(1).Row):D$($Y1.item($Y1.count).Row),F$($X1.item(1).Row):F$($X1.item($X1.count).Row)")
$NsxManagerResourcesHistoricChart.SetSourceData($chartdata1)
$RangeToCover = $NsxManagerWorkSheet.Range("D47:F67")
$ChartObj = $NsxManagerResourcesHistoricChart.Parent
$ChartObj.Top = $RangeToCover.Top
$ChartObj.Left = $RangeToCover.Left
$ChartObj.Height = $RangeToCover.Height
$ChartObj.Width = $RangeToCover.Width
However once i did this the Chart Name is changed to be Memory (Wich is the second column) and the reading did not include the CPU (Only the Memory)
Also getting an error related to the ChartTitle as below:
The property 'Text' cannot be found on this object. Verify that the property exists and can be set.
At line:821 char:5
+ $NsxManagerResourcesHistoricChart.ChartTitle.Text = "NSX Manager ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
Not sure what is the issue here.
Graph Output after adding the above 2 lines is as follow graph after editing

Delete duplicate rows in excel (.xls) using powershell script

I'm having troubles with a script. I need to remove all the duplicate rows in my XLS file.
Here's my script:
sdsfsdf
$out_fcalias = "D:\scripts\SAN\Out_fcAlias.txt"
$out_flogi = "D:\scripts\SAN\Out_flogi.txt"
$out_zone = "D:\scripts\SAN\Out_zone.txt"
$out_zoneact = "D:\scripts\SAN\Out_zoneactive.txt"
$Final_Report= "D:\Scripts\SAN\Report_test.xls"
# Params
$i = ""
$tmp_splitArray = ""
$tmp_SwitchName = ""
$tmp_FabricName = ""
$tmp_ZoneName = ""
$tmp_Fcid = ""
$tmp_WWNName = ""
$tmp_Output = ""
# create xls
$XLS = new-object -comobject excel.application
$XLS.Visible = $True
$XLS_File = $XLS.Workbooks.Add()
$XLS_Sheet = $XLS_File.Worksheets.Item(1)
$XLS_Sheet.Name = "Report"
$XLS_Sheet.Cells.Item(1,1) = "Fabric"
$XLS_Sheet.Cells.Item(1,2) = "Zone"
$XLS_Sheet.Cells.Item(1,3) = "Fcid"
$XLS_Sheet.Cells.Item(1,4) = "WWN"
$XLS_Sheet.Cells.Item(1,5) = "Switch"
$XLS_Sheet.Cells.Item(1,6) = "FCID"
$XLS_Sheet.Cells.Item(1,7) = "Port Name"
$XLS_Sheet.Cells.Item(1,8) = "Node Name"
$XLS_Sheet.Cells.Item(1,9) = "Alias"
$XLS_LineCounter = 2
$a = get-content $out_zoneact
foreach ( $i in $a)
{
if ($i -match "Fabric") { $tmp_FabricName = $i}
if ($i -match "zone name")
{
$tmp_splitArray = [regex]::split($i, " ")
$tmp_ZoneName = $tmp_splitArray[2]
}
if ($i -match " fcid ")
{
$tmp_splitArray = [regex]::split($i, " ")
$tmp_Fcid = $tmp_splitArray[2]
}
if ($i -match "pwwn")
{
$tmp_splitArray = [regex]::split($i, " ")
$tmp_WWNName = $tmp_splitArray[4]
$XLS_Sheet.cells.item($XLS_LineCounter,1) = $tmp_FabricName
$XLS_Sheet.cells.item($XLS_LineCounter,2) = $tmp_ZoneName
$XLS_Sheet.cells.item($XLS_LineCounter,3) = $tmp_Fcid
$XLS_Sheet.cells.item($XLS_LineCounter,4) = $tmp_WWNName.Substring(0,$tmp_WWNName.Length-1)
$XLS_LineCounter = $XLS_LineCounter + 1
}
}
#autofit
$objRange = $XLS_Sheet.UsedRange
[void] $objRange.EntireColumn.Autofit()
$XLS_File.SaveAs($Final_Report)
$XLS_File.Close()
$XLS.Quit()
So I have a lot of duplicate rows, and I need to get rid of them programmatically, so I can put it in my script.
after # autofit, insert
$XLS_Sheet.UsedRange.RemoveDuplicates()
should work, as provided in MSDN
Sorry to update an old thread, but I spent a while working out why this didn't work. With regard to Mat M's solution, I find that you need to specfy the column indexes in an array as an argument.
$cols = 1,2,3,4,5,6,7,8,9
$XLS_Sheet.UsedRange.RemoveDuplicates($cols)

Resources