I can set form elements inside hashtable:
$Hash = #{}
$Hash.Main = New-Object System.Windows.Forms.Form
$Hash.Main.Left = 0
$Hash.Main.Top = 0
...
$Hash.Label = New-Object System.Windows.Forms.Label
$Hash.Label.Left = 0
$Hash.Label.Top = 0
...
$Hash.Panel = New-Object System.Windows.Forms.Panel
$Hash.Panel.Left = 0
$Hash.Panel.Top = 0
...
How can I write the same thing inside hashtable? I tried to make it as if it could be. And it works. But is this syntax correct?
$Hash = #{
Main = [System.Windows.Forms.Form] #{
Left = 0
Top = 0
...
}
Label = [System.Windows.Forms.Label] #{
Left = 0
Top = 0
...
}
Panel = [System.Windows.Forms.Panel] #{
Left = 0
Top = 0
...
}
}
Thank you
Yes, this syntax is correct:
Creating Objects from Hash Tables
Beginning in PowerShell 3.0, you can create an object from a hash
table of properties and property values.
The syntax is as follows:
[<class-name>]#{
<property-name>=<property-value>
<property-name>=<property-value>
…
}
This method works only for classes that have a null constructor,
that is, a constructor that has no parameters. The object properties
must be public and settable.
For more information, see about_Object_Creation.
Check the first condition (a constructor that has no parameters):
[System.Drawing.Font], ### does not have empty constructor
[System.Windows.Forms.Form],
[System.Windows.Forms.Label],
[System.Windows.Forms.Panel] |
Where-Object {
'new' -in ( $_ |
Get-Member -MemberType Methods -Static |
Select-Object -ExpandProperty Name ) -and
$_::new.OverloadDefinitions -match ([regex]::Escape('new()'))
} | Select-Object -ExpandProperty FullName
System.Windows.Forms.Form
System.Windows.Forms.Label
System.Windows.Forms.Panel
Check the latter condition (object properties must be public and settable):
[System.Windows.Forms.Form],
[System.Windows.Forms.Label],
[System.Windows.Forms.Panel] |
ForEach-Object {
#{ $_.FullName = (
$_.GetProperties('Instance,Public') | Where-Object CanWrite |
Select-Object -ExpandProperty Name | Sort-Object
)
}
}
Name Value
---- -----
System.Windows.Forms.Form {AcceptButton, AccessibleDefaultActionDescription, Acc...
System.Windows.Forms.Label {AccessibleDefaultActionDescription, AccessibleDescrip...
System.Windows.Forms.Panel {AccessibleDefaultActionDescription, AccessibleDescrip...
Getting both above code snippets together is a trivial task…
Related
I have a hashtable of IP connections that are associated to their Destination Prefixes. Here is the code to gather it all together:
function Get-InterfaceRoutes {
$interfaceIPs = Get-NetIPConfiguration -Detailed |
Where-Object { $_.netadapter.status -eq 'up' } | Get-NetIPAddress -AddressFamily IPv4 |
Select-Object -Property IPAddress, InterfaceIndex, InterfaceAlias
Foreach ($interfaceIP in $interfaceIPs) {
$route = Get-NetRoute -InterfaceIndex ($interfaceIP.InterfaceIndex) |
Select-Object -Property ifINdex, DestinationPrefix, NextHop, RouteMetric, ifMetric |
Where-Object -Property DestinationPrefix -like '*.*.*.*' | Sort-Object -Property ifIndex
[PSCustomObject]#{
Index = ($interfaceIp.InterfaceIndex)
Address = ($interfaceIP.IPAddress)
Alias = ($interfaceIP.InterfaceAlias)
DestinationPrefix = ($route.DestinationPrefix)
NextHop = ($route.NextHop)
RouteMetric = ($route.RouteMetric)
InterfaceMetric = ($route.InterfaceMetric)
}
}
}
$collection = #(Get-InterfaceRoutes)
I am building a UI in PS-5.1(WinForms) to list the various indexes and their properties. With it I have this button that I want to be able to select one of the listed Destination Prefixes (of which there will be at least 1, at most n to choose from) associated with each index (again, 1-n):
$destinationSelectButton.Add_Click({
$selectedDestination = $collection.keys |
Out-GridView -Title "Select Destination Prefix" -PassThru |
ForEach-Object { $_.Values } | Select-Object -Property DestinationPrefix
Write-Host $selectedDestination | Out-String #<<<exists for confirmation in console, ignore.
})
The problem I have with this snippet specifically is that when I select the button, I don't get the GridView box to select from the list of Prefixes. Just nothing. No error message, no window opening, just an acknowledgement in my terminal that the button was clicked.
If I arrange the code any other way, such as:
$selectedDestination = $collection |
Out-Gridview -Title "Select Destination Prefix" -PassThru |
Select-Object -Property DestinationPrefix
I get this:
Here the Destination Prefix is gathered as one object, but I want to display that array broken apart so that one can be selected from the list and sent to $selectedDestination for use later on. I suspect the code block I shared for the button SHOULD do just that, but without the window opening, and no error to say why, I am not sure where to go from here to get it to work.
If I understand correctly, you're just needing to loop through each object resulted from Get-NetRoute and then combine / merge that output with the result of Get-NetIPConfiguration, instead of merging all objects into one object.
For that you can use Select-Object with calculated properties:
$interfaceIPs = Get-NetIPConfiguration -Detailed |
Where-Object { $_.NetAdapter.Status -eq 'up' } |
Get-NetIPAddress -AddressFamily IPv4
$collection = foreach($interfaceIP in $interfaceIPs) {
Get-NetRoute -InterfaceIndex $interfaceIP.InterfaceIndex |
Where-Object -Property DestinationPrefix -like '*.*.*.*' |
Sort-Object -Property ifIndex | Select-Object #(
#{ N = 'Index'; E = { $interfaceIp.InterfaceIndex }}
#{ N = 'Address'; E = { $interfaceIP.IPAddress }}
#{ N = 'Alias'; E = { $interfaceIP.InterfaceAlias }}
'DestinationPrefix'
'NextHop'
'RouteMetric'
'InterfaceMetric'
)
}
$selection = $collection | Out-GridView -PassThru
I have a 100 column table in sql server and I want to make it so not all of the columns need to be passed in the file to load. I have assigned column names in a table that then compares the columns in a hash table to find matching columns. I then create the code based on the match for the array I want to use to insert the data from the file. The problem is, it doesn't like calling the one variable to create the custom object.
I store the following below in a array. (up to a 100 of these, few below for sample (notice sqlcolumn2 is skipped for example)).
sqlcolumn1 = if ([string]::IsNullOrEmpty($obj.P1) -eq $true) {$null} else {"$obj.P1"}
sqlcolumn3 = if ([string]::IsNullOrEmpty($obj.P2) -eq $true) {$null} else {"$obj.P2"}
sqlcolumn4 = if ([string]::IsNullOrEmpty($obj.P3) -eq $true) {$null} else {"$obj.P3"}
sqlcolumn5 = if ([string]::IsNullOrEmpty($obj.P4) -eq $true) {$null} else {"$obj.P4"}
Here is the array:
foreach($line in $Final)
{
$DataRow = "$($line."TableColumnName") = if ([string]::IsNullOrEmpty(`$obj.$($line."PName")) -eq `$true) {`$null} else {`"`$obj.$($line."PName")`"}"
$DataArray += $DataRow
}
I then try to add it to a final array where I would want this to be looped through for each row of data after which I would perform the insert from the array. Even though the "string" value in the array above is correct if it were hand coded, I can't get it to recognize the rows and run.
foreach ($obj in $data2)
{
$test = [PSCustomObject] #{
$DataArray = Invoke-Expression $DataArray
}
If I just type $DataArray, it doesn't like this because it wants the = sign which I already have built into the string.
Is what I am trying to do even possible.
I was attempting to template out various different ways we receive this data, where some people send us 30 of the 100 columns, other more or less, and no one person using the exact columns to cut down on individual scripts for everything.
Adding more code:
Function ArrayCompare() {
[CmdletBinding()]
PARAM(
[Parameter(Mandatory=$True)]$Array1,
[Parameter(Mandatory=$True)]$A1Match,
[Parameter(Mandatory=$True)]$Array2,
[Parameter(Mandatory=$True)]$A2Match)
$Hash = #{}
foreach ($Data In $Array1) {
$Hash[$Data.$A1Match] += ,$Data
}
foreach ($Data In $Array2) {
$Hash[$Data.$A2Match] += ,$Data
}
foreach ($KeyValue In $Hash.GetEnumerator()){
$Match1, $Match2 = $KeyValue.Value.Where( {$_.$A1Match}, 'Split')
[PSCustomObject]#{
MatchValue = $KeyValue.Key
A1Matches = $Match1.Count
A2Matches = $Match2.Count
TablePosition = [int]$Match2.TablePosition
TableColumnName = $Match2.TableColumnName
# PName is the P(##) that is a generic ascending column value back to import-excel module. ColumnA = P1, ColumnB = P2 etc..until no data is detected. Allows flexibility and not having to know how many columns there are
PName = $Match1.Name}
}
}
$Server = 'ServerName'
$Catalog = 'DBName'
$DestinationTable = 'ImportIntoTableName'
$FileIdentifierID = 10
$FileName = 'Test.xlsx'
$FilePath = 'C:\'
$FullFilePath = $FilePath + $FileName
$data = Import-Excel -Path $FullFilePath -NoHeader -StartRow 1 # Import-
Excel Module for working with xlsx excel files
$data2 = Import-Excel -Path $ullFilePath -NoHeader -StartRow 2 # Import-
Excel Module for working with xlsx excel files
$ExpectedHeaderArray = #()
$HeaderArray = #()
$DataArray = #()
$HeaderDetect = #()
$HeaderDetect = $data | Select-Object -First 1 # Header Row In File
$HeaderDetect |
ForEach-Object {
$ColumnValue = $_
$ColumnValue |
Get-Member -MemberType *Property |
Select-Object -ExpandProperty Name |
ForEach-Object {
$HeaderValues = [PSCustomObject]#{
Name = $_
Value = $ColumnValue.$_}
$HeaderArray += $HeaderValues
}
}
# Query below provides a list of all expected file headers and the table
column name they map to
$Query = "SELECT TableColumnName, FileHeaderName, TablePosition FROM
dbo.FileHeaders WHERE FileIdentifierID = $($FileIdentifierID)"
$ds = Invoke-Sqlcmd -ServerInstance $Server -Database $Catalog -Query $Query
-OutputAs DataSet
$ExpectedHeaderArray = foreach($Row in $ds.Tables[0].Rows)
{
new-object psObject -Property #{
TableColumnName = "$($row.TableColumnName)"
FileHeaderName = "$($row.FileHeaderName)"
TablePosition = "$($row.TablePosition)"
}
}
#Use Function Above
#Bring it together so we know what P(##) goes with which header in file/mapped to table column name
$Result = ArrayCompare -Array1 $HeaderArray -A1Match Value -Array2 $ExpectedHeaderArray -A2Match FileHeaderName
$Final = $Result | sort TablePosition
foreach($Line in $Final)
{
$DataRow = "$($Line."TableColumnName") = if ([string]::IsNullOrEmpty(`$obj.$($Line."PName")) -eq `$true) {`$null} else {`"`$obj.$($Line."PName"))`"}"
$DataArray += $DataRow
}
# The output below is what the code inside the last array would be that I would use to import into excel.
# The goal is to be dynamic and match headers in the file to the stored header value and import into a table (mapped from header column to table column name)
# The reason for this is before I was here, there were many different "versions" of a layout that was given out. In the end, it is all one in the same
# but some send all 100 columns, some only send a handful, some send 80 etc. I am trying to have everything flow through here vs. 60+ pieces of code/stored procedures/ssis packs
Write-Output $DataArray
# Output Sample -- Note how in the sample, P2 and subsequent skip SQLColumn2 because P2 maps to the header value of position 3 in the sql table and each after is one off.
# In this example, SqlColumn2 would not be populated
# SqlColumn1 = if ([string]::IsNullOrEmpty($obj.P1) -eq $true) {$null} else {"$obj.P1"}
# SqlColumn3 = if ([string]::IsNullOrEmpty($obj.P2) -eq $true) {$null} else {"$obj.P2"}
# SqlColumn4 = if ([string]::IsNullOrEmpty($obj.P3) -eq $true) {$null} else {"$obj.P3"}
# SqlColumn5 = if ([string]::IsNullOrEmpty($obj.P4) -eq $true) {$null} else {"$obj.P4"}
# I know this doesn't work. This is where I'm stuck, how to build an array now off of this output from above
foreach ($obj in $data2)
{
$test = [PSCustomObject] #{
$DataArray = Invoke-Expression $DataArray}
}
I'm gong to re-state your question first, just to make sure I understand it properly (it's possible I don't!)...
You've got an excel file that looks something like this:
+---+---------+---------+---------+
| | A | B | C |
+---+---------+---------+---------+
| 1 | HeaderA | HeaderB | HeaderC |
+---+---------+---------+---------+
| 2 | Value P | Value Q | Value R |
+---+---------+---------+---------+
| 3 | Value S | Value T | Value U |
+---+---------+---------+---------+
You've also got a database table which looks like this:
+---------+---------+---------+---------+
+ ColumnW | ColumnX | ColumnY | ColumnZ |
+---------+---------+---------+---------+
+ ....... | ....... | ....... | ....... |
+---------+---------+---------+---------+
and a column mapping table like this (note, ColumnX isn't mapped in this example):
+-----------------+----------------+---------------+
| TableColumnName | FileHeaderName | TablePosition |
+-----------------+----------------+---------------+
| ColumnW | HeaderA | 1 |
+-----------------+----------------+---------------+
| ColumnY | HeaderB | 2 |
+-----------------+----------------+---------------+
| ColumnZ | HeaderC | 3 |
+-----------------+----------------+---------------+
You want to insert the values from the spreadsheet into the database table, using the data in your mapping table so you get this:
+---------+---------+---------+---------+
+ ColumnW | ColumnX | ColumnY | ColumnZ |
+---------+---------+---------+---------+
+ Value P | null | Value Q | Value R |
+---------+---------+---------+---------+
+ Value S | null | Value T | Value U |
+---------+---------+---------+---------+
So let's load the spreadsheet (letting the header row generate meaningful property names this time):
$data = Import-Excel -Path ".\MySpreadsheet.xlsx";
write-host ($data | ft | out-string);
# HeaderA HeaderB HeaderC
# ------- ------- -------
# Value P Value Q Value R
# Value S Value T Value U
and get your column mapping data (I'm programmatically creating an in-memory dataset, but you obviously read yours from your database instead):
$mappings = new-object System.Data.DataTable;
$null = $mappings.Columns.Add("TableColumnName", [string]);
$null = $mappings.Columns.Add("FileHeaderName", [string]);
$null = $mappings.Columns.Add("TablePosition", [int]);
#(
#{ "TableColumnName"="ColumnW"; "FileHeaderName"="HeaderA"; "TablePosition"=1 },
#{ "TableColumnName"="ColumnY"; "FileHeaderName"="HeaderB"; "TablePosition"=2 },
#{ "TableColumnName"="ColumnZ"; "FileHeaderName"="HeaderC"; "TablePosition"=3 }
) | % {
$row = $mappings.NewRow();
$row.TableColumnName = $_.TableColumnName;
$row.FileHeaderName = $_.FileHeaderName;
$row.TablePosition = $_.TablePosition;
$mappings.Rows.Add($row);
}
$ds = new-object System.Data.DataSet;
$ds.Tables.Add($mappings);
write-host ($ds.Tables[0] | ft | out-string)
# TableColumnName FileHeaderName TablePosition
# --------------- -------------- -------------
# ColumnW HeaderA 1
# ColumnY HeaderB 2
# ColumnZ HeaderC 3
Now we can build the "mapped" objects:
$values = #();
foreach( $row in $data )
{
$properties = [ordered] #{};
foreach( $mapping in $mappings )
{
$properties.Add($mapping.TableColumnName, $row."$($mapping.FileHeaderName)");
}
$values += new-object PSCustomObject -Property $properties;
}
write-host ($values | ft | out-string)
# ColumnW ColumnY ColumnZ
# ------- ------- -------
# Value P Value Q Value R
# Value S Value T Value U
The tricksy bit is $properties.Add($mapping.TableColumnName, $row."$($mapping.FileHeaderName)"); - basically, you can access object properties in PowerShell using a dotted string literal or variable (I'm not sure of the exact feature name) - e.g.
PS> $myValue = new-object PSCustomObject -Property #{ "aaa"="bbb"; "ccc"="ddd" }
PS> $myValue."aaa"
bbb
PS> $myProperty = "aaa"
PS> $myValue.$myProperty
"bbb"
so $row."$($mapping.FileHeaderName)" is an expression that evaluates to the value of the property of $row named in $mapping.FileHeaderName.
And then finally you can insert the objects into your database using your existing process...
Note that I couldn't quite work out what your ArrayCompare is actually doing so it's possible the above doesn't solve your problem 100%, but it's hopefully close enough that you can either work the difference out yourself, or leave a comment with where it differs from your desired solution.
Hope this helps.
I am pulling data from an API that ConnectWise offers. I am trying to pull a list of usernames and password and put them in to a format which I can either reference in another script (or combiner with this one), or that I can export to a CSV. I'd prefer the first if possible.
The code:
Function Get-CWConfiguration
{
[string]$BaseUri = "$CWServerRoot"
[string]$Accept = "application/vnd.connectwise.com+json; version=v2015_3"
[string]$ContentType = "application/json"
[string]$Authstring = $CWInfo + '+' + $CWCredentials1 + ':' + $CWCredentials2
$encodedAuth = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(($Authstring)));
$Headers=#{"Authorization"="Basic $encodedAuth"}
Invoke-RestMethod -URI $BaseURI -Headers $Headers -ContentType $ContentType -Method Get
}
$username = (Get-CWConfiguration).questions | Where-Object {($_.questionid -eq 419)} | Sort-Object -Property questionid | select answer
$password = (Get-CWConfiguration).questions | Where-Object {($_.questionid -eq 420)} | Sort-Object -Property questionid | select answer
Everything above the $username variable is the stuff connecting to the API and I did not modify that. The code below is the best way I found to pull the info that I need. This is returning each variable as an array, which is fine but if that happens I need to have an array with 2 columns. 1 named Username and the other named Password. if I do a $username | Get-Member it returns:
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
answer NoteProperty string answer=admin#admin.com
My end goal is to have a variable like $credentials output something that displays like:
Username Password
-------- ----------
admin1#admin.com Password1
admin2#admin.com Password2
admin3#admin.com Password3
Most methods I have tried have resulted in everything put output to 1 line or 1 column. I'm not sure if I should be combining the arrays and renaming the $username.answer and $password.answer fields or creating a PSObject? My main difficulty has been that both variables have that same answer NoteProperty
You'd want to create new objects with the expanded properties of the current objects. This could all look something like this (note that I'm manually creating analogs for what you're all dealing with and ignoring the string manipulation you'll likely have to do)
$Username = New-Object -TypeName pscustomobject -Property #{Answer = "Answer:Hithisispatrick"}
$Password = New-Object -TypeName pscustomobject -Property #{Answer = "Answer:HelloThisisSquidward"}
$UsernameAnswer = $Username | Select -ExpandProperty Answer
$PasswordAnswer = $Password | Select -ExpandProperty Answer
$Final = New-Object -TypeName pscustomobject -Property #{UserName= $UsernameAnswer ; Password = $PAsswordAnswer}
This should give you output something like this:
UserName Password
-------- --------
Answer:Hithisispatrick Answer:HelloThisisSquidward
Then if you want to parameterize it/Expand it, you should be able then to toss it in to a foreach loop and have it output the Custom Object, setting that equal to an array that then builds out of those objects, like so(I'll use while to make it simpler to show):
$Count = 0
$Username = New-Object -TypeName pscustomobject -Property #{Answer = "Answer:Hithisispatrick"}
$Password = New-Object -TypeName pscustomobject -Property #{Answer = "Answer:HelloThisisSquidward"}
$Array = While ($Count -lt 5){
$UsernameAnswer = $Username | Select -ExpandProperty Answer
$PAsswordAnswer = $Password | Select -ExpandProperty Answer
$Final = New-Object -TypeName pscustomobject -Property #{UserName= $UsernameAnswer ; Password = $PAsswordAnswer}
$Final
$Count += 1
}
$Array
This produces something like this:
Password UserName
-------- --------
Answer:HelloThisisSquidward Answer:Hithisispatrick
Answer:HelloThisisSquidward Answer:Hithisispatrick
Answer:HelloThisisSquidward Answer:Hithisispatrick
Answer:HelloThisisSquidward Answer:Hithisispatrick
Answer:HelloThisisSquidward Answer:Hithisispatrick
I'm trying to create a custom object based on server names from a text file.
The script I have goes and imports the txt file into a Variable. Then runs a foreach server in the servers variable to create the custom object. I would like to be able to output the object's properties as a table that doesn't include the header info each time.
See script and output below:
$SERVERS = gc c:\servers.txt
foreach ($srv in $SERVERS)
{
$Obj = New-Object PsObject -Property`
#{
Computername = $srv
SecurityGroup = (Get-QADComputer $srv).memberof
RebootDay = ((Get-QADComputer $srv).memberof).split(',').split(' ')[2]
Combined = ((Get-QADComputer $srv).memberof).split(',').split(' ').split('=')[1]
RebootTime = $obj.combined.substring(0,4)
}
echo $obj | ft Computername,RebootDay -autosize
}
This is the output currently:
Computername RebootDay
SERVER007 Sunday
Computername RebootDay
SERVER009 Sunday
Computername RebootDay
SERVER003 Sunday
I'd like it to look more like:
Computername RebootDay
SERVER007 Sunday
SERVER001 Sunday
SERVER009 Sunday
TessellatingHeckler was on the right track really. The issue with his code is that you can't pipe a ForEach($x in $y){} loop to anything (not to be confused with a ForEach-Object loop that you usually see shortened to just ForEach like $Servers | ForEach{<code here>}) You don't want to pipe objects to Format-Table one at a time, you want to pipe a collection of objects to it so that it looks nice. So here's the modified code:
$SERVERS = gc c:\servers.txt
$Results = foreach ($srv in $SERVERS)
{
New-Object PsObject -Property #{
Computername = $srv
SecurityGroup = (Get-QADComputer $srv).memberof
RebootDay = ((Get-QADComputer $srv).memberof).split(',').split(' ')[2]
Combined = ((Get-QADComputer $srv).memberof).split(',').split(' ').split('=')[1]
RebootTime = $obj.combined.substring(0,4)
}
}
$Results | FT ComputerName,RebootDay -auto
That collects the objects in an array, then you pass the whole array to Format-Table
Don't put the "ft" (Format-Table) command inside the loop, put it outside, once, at the end. e.g.
$SERVERS = gc c:\servers.txt
$results = foreach ($srv in $SERVERS)
{
$Obj = New-Object PsObject -Property`
#{
Computername = $srv
SecurityGroup = (Get-QADComputer $srv).memberof
RebootDay = ((Get-QADComputer $srv).memberof).split(',').split(' ')[2]
Combined = ((Get-QADComputer $srv).memberof).split(',').split(' ').split('=')[1]
RebootTime = $obj.combined.substring(0,4)
}
$Obj
}
$results | ft Computername,RebootDay -autosize
Edit: Fixed for foreach pipeline bug.
You could possibly neaten it a bit because you don't need to make a new PSObject for a hashtable, and then put the object into the pipeline; you don't need to repeat the Get-QADComputer commands three times. I'm suspicious that the $obj.combined line isn't doing anything - how can you refer to an object inside the properties of the new-object call, before it gets assigned that name? And the repeated splits could probably be combined because it operates on individual characters, not strings.
gc c:\servers.txt | foreach {
$memberof = (Get-QADComputer $_).memberof
#{
Computername = $_;
SecurityGroup = $memberof;
RebootDay = $memberof.split(', ')[2];
Combined = $memberof.split(', =')[1];
# ?? RebootTime = $obj.combined.substring(0,4)
}
} | ft Computername,RebootDay -autosize
I have followed different posts on the web to fix this issue but my code still returns a single element insteaf of array. My code below:
Add-PSSnapin -Name VeeamPSSnapIn -WarningAction SilentlyContinue
$sessionVMSummary = #()
$bkJobs = get-vbrjob | foreach {
$session = $_.findlastsession()
if (($session -ne $NULL) -and ($_.isScheduleEnabled -eq $TRUE)) {
# Get session details
$sessionDocument = New-Object PSObject -Property #{
"Name" = $session.JobName
"Result" = $session.Result.toString()
"ObjectStatus" = #()
}
[Veeam.Backup.Core.CBackupTaskSession]::GetByJobSession($session.id) | foreach {
$Info = New-Object PSObject -Property #{
"Start Time" = $_.Progress.StartTime
"End Time" = $_.Progress.StopTime
"Duration" = $_.Progress.Duration
}
$sessionDocument.ObjectStatus += $Info
}
$sessionVMSummary += $sessionDocument
}
}
return $sessionVMSummary
Question 1: How can I make $sessionVMSummary to return an array whith 1 element?
Question 2: How can I make my code more efficient from the grammar point of view?
thanks
Use the comma operator to wrap your array in another array e.g.:
return ,$sessionVMSummary