Why isn't the conditional statement working right? - powershell

I've got some Reports that I'm trying to loop through, and fetch the connection ID's (User ID's) and list those reports along with the usernames.
A report can have the following scenarios:
No DataSources
1 DataSource (1 User ID)
More than 1 DataSources (Therefore more than 1 user id's)
The following script does the job, however, for some reason, reports with only 1 datasource seem to be getting executed in the else ... No Connection ID's found! statement. That shouldn't be the case considering there is AT LEAST 1 Datasource, so they should be going through this if ($DataSourceValue.DataModelDataSource.count -gt 0) statement instead!
Below is script accompanied by current output vs expected output:
$loopCount = 1
$PBI_Reports_Array = #()
$DataSourceQueue = New-Object System.Collections.Queue
try {
$PBI_Reports_Array = $(Invoke-RestMethod -UseDefaultCredentials -uri $($webPortalURL + "/api/v2.0/PowerBIReports"))
foreach ($reportPath in $PBI_Reports_Array.value.path) {
try {
foreach ($DataSource in $(Invoke-RestMethod -UseDefaultCredentials -uri $($webPortalURL + "/api/v2.0/PowerBIReports(path='" + $reportPath + "')/DataSources")))
{
$DataSourceQueue.Enqueue($DataSource)
}
while($DataSourceQueue.count)
{
$DataSourceValue = $($DataSourceQueue.Dequeue()).value
if ([string]::IsNullOrEmpty($($DataSourceValue))) {
write-host "$loopCount | $reportPath | No DataSource connection exists for this Report!";
}
else {
if ($DataSourceValue.DataModelDataSource.count -gt 0) #if there is at least 1+ DataSources and usernames...
{
#because there is more than 1 DataSources, that means there's also more than 1 connection ID and more than 1 connection ID's
#to loop through both of those variables, foreach loop would not be suitable for more than 1 variable,
#so we use good old for loop
0..($DataSourceValue.DataModelDataSource.length-1) | ForEach-Object {
write-host "$loopCount | $reportPath | $($DataSourceValue.DataModelDataSource[$_].Username) | Retrieved!"
}
}
else
{
write-host "$loopCount | $reportPath | $($DataSourceValue.DataModelDataSource.Username) | No Connection ID's found!"
}
}
}
#$loopCount++
}
catch {
write-host "$loopCount | ERROR! $($error[0])`r`n$($error[0].InvocationInfo.PositionMessage)`r`n$($error[0].ScriptStackTrace)"
}
$loopCount++
}
}
catch {
}
Current output:
1 | /Cash Flow/CFG | SI_123456_P | No Connection ID's found!
2 | /CPUR/DQ Dashboards | gp_powerbi_cpur | No Connection ID's found!
3 | /ABC/DQ Dashboards/PreCost ABC DQ Dashboard | gp_powerbi_cpur | Retrieved!
3 | /ABC/DQ Dashboards/PreCost ABC DQ Dashboard | SI_123456_P | Retrieved!
4 | /Prototypes/ARCHIVE/dummy data | | No Connection ID's found!
Expected Output:
1 | /Cash Flow/CFG | SI_123456_P | Retrieved!
2 | /CPUR/DQ Dashboards | gp_powerbi_cpur | Retrieved!
3 | /ABC/DQ Dashboards/PreCost ABC DQ Dashboard | gp_powerbi_cpur | Retrieved!
3 | /ABC/DQ Dashboards/PreCost ABC DQ Dashboard | SI_123456_P | Retrieved!
4 | /Prototypes/ARCHIVE/dummy data | | No Connection ID's found!
Note the 4th report has no connection ID's, therefore makes sense that the status is No Connection ID's found!. but reports 1 and 2 have 1 ID, so the status should be Retrieved! not No Connection ID's found! as it's currently displaying. For the 3rd report, it appears because it has more than 1 DataSource, the conditional statement is being applied correctly...
EDIT:
$DataSourceValue.DataModelDataSource.GetType()
yields:
for reports 1 & 2:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
for report 3:
True True Object[] System.Array
EDIT 2:
62 | /test/BMI vs Chocolate | | Retrieved!
Type : Import
Kind : File
AuthType : Windows
SupportedAuthTypes : {Windows}
Username :
Secret :
ModelConnectionName :
62 | /test/BMI vs Chocolate | | Retrieved!
Type : Import
Kind : File
AuthType : Windows
SupportedAuthTypes : {Windows}
Username :
Secret :
ModelConnectionName :
62 | /test/BMI vs Chocolate | | Retrieved!
Type : Import
Kind : File
AuthType : Windows
SupportedAuthTypes : {Windows}
Username :
Secret :
ModelConnectionName :
63 | /VP/Complexity_PROD | gp_powerbi_vp | Retrieved!
Id : 12345-cvgfgh7-87964-e76ufhf5
Name :
Description :
Path :
Type : DataSource
Hidden : False
Size : 0
ModifiedBy : user1
ModifiedDate : 2021-02-03T12:17:26.413-05:00
CreatedBy : SI_123456_P
CreatedDate : 2021-02-03T12:13:42.523-05:00
ParentFolderId :
IsFavorite : False
ContentType :
Content :
IsEnabled : True
ConnectionString : db=maxisdb;driver={DataDirect 7.1 Greenplum Wire Protocol};em=1;host=gp.companyxyz.com;port=5432;vsc=0
DataSourceType :
IsOriginalConnectionStringExpressionBased : False
IsConnectionStringOverridden : False
CredentialRetrieval : prompt
IsReference : False
DataSourceSubType : DataModel
Roles : {}
CredentialsByUser :
CredentialsInServer :
DataModelDataSource : #{Type=Import; Kind=Odbc; AuthType=UsernamePassword; SupportedAuthTypes=System.Object[]; Username=gp_powerbi_vp; Secret=; ModelConnectionName=}
Type : Import
Kind : Odbc
AuthType : UsernamePassword
SupportedAuthTypes : {UsernamePassword, Anonymous, Windows}
Username : gp_powerbi_vp
Secret :
ModelConnectionName :

I don't mean this as an answer but could you test your script by replacing this portion of code:
$DataSourceValue = $($DataSourceQueue.Dequeue()).value
if ([string]::IsNullOrEmpty($($DataSourceValue))) {
write-host "$loopCount | $reportPath | No DataSource connection exists for this Report!";
}
else
{
if ($DataSourceValue.DataModelDataSource.count -gt 0)
{
0..($DataSourceValue.DataModelDataSource.length-1) | ForEach-Object {
write-host "$loopCount | $reportPath | $($DataSourceValue.DataModelDataSource[$_].Username) | Retrieved!"
}
}
else
{
write-host "$loopCount | $reportPath | $($DataSourceValue.DataModelDataSource.Username) | No Connection ID's found!"
}
}
For this:
$DataSourceValue = $DataSourceQueue.Dequeue().Value
if (-not $DataSourceValue)
{
write-host "$loopCount | $reportPath | No DataSource connection exists for this Report!";
}
else
{
if ($DataSourceValue.DataModelDataSource.Username)
{
foreach($i in $DataSourceValue.DataModelDataSource.Username)
{
write-host "$loopCount | $reportPath | $i | Retrieved!"
}
}
else
{
write-host "$loopCount | $reportPath | $($DataSourceValue.DataModelDataSource.Username) | No Connection ID's found!"
}
}
Edit: Complete new script here, let's see if this works.
$ErrorActionPreference = 'Stop'
$loopCount = 1
$hash = #{
UseDefaultCredentials = $true
}
try
{
$hash.Uri = "$webPortalURL/api/v2.0/PowerBIReports"
$PBI_Reports_Array = (Invoke-RestMethod #hash).Value.Path
foreach ($reportPath in $PBI_Reports_Array)
{
$hash.Uri = "$webPortalURL/api/v2.0/PowerBIReports(path='$reportPath')/DataSources"
try
{
$DataSourceQueue = (Invoke-RestMethod #hash).Value
}
catch
{
Write-Warning ("$loopCount | ERROR! Can't connect to {0}" -f $hash.uri)
continue
}
foreach ($value in $DataSourceQueue)
{
if (-not $value.DataModelDataSource)
{
write-host "$loopCount | $reportPath | No DataModelDataSource"
continue
}
foreach($i in $value.DataModelDataSource)
{
if($i.Username)
{
$i.Username | foreach-object {
write-host "$loopCount | $reportPath | $_ | Retrieved!"
}
}
else
{
write-host "$loopCount | $reportPath | DataModelDataSource Found but No Usernames"
}
}
}
$loopCount++
}
}
catch
{
Write-Warning ("ERROR! Can't connect to {0}" -f $hash.uri)
}

Related

Test battery status using PowerShell

I'm trying to use PowerShell to tell me when my computer is on battery or AC Power.
I want my script to send me a windows notification when my laptop's charger unplugs.
For the moment, I try to use a recursive fonction to test my battery status every 5 seconds but it doesn't work...
Please, be indulgent about my level, I didn't know anything about PowerShell 3 hours ago... And the last time I coded something was a long time ago !
Function Test-IsOnBattery
{
$battery = Get-WmiObject Win32_Battery
If ($battery.BatteryStatus -eq 2) {
Write-Host "PC sur secteur."
Start-Sleep -Seconds 5
return Test-IsOnBattery
}
Else {
Write-Host "PC sur batterie."
New-BurntToastNotification -Text "Battery Notification" , "Batterie plus sur secteur !"
}
}
Nathan,
Here's a script you can use that you can run from a Scheduled Task, rather than a loop, and have it start on boot up and repeat every so many minutes.
<#+---------------------------------------------------------------------------+
| PowerShell Pgm: BatteryStatus.ps1 |
| Programmed By : The Computer Mentor |
| aka : RetiredGeek # askWoody.com & StackOverFlow.com |
| Created : 06 Mar 2013 |
| Last Updated : 23 Jan 2023 | |
| Current Ver. : 6.0 |
+---------------------------------------------------------------------------+
#>
Clear-Host
Add-Type -AssemblyName "System.Windows.Forms"
$StatusMsg = {
[Windows.Forms.MessageBox]::Show($Message, $Title,
[Windows.Forms.MessageBoxButtons]::OK ,
[Windows.Forms.MessageBoxIcon]::Information)}
$Message = ""
$Title = "Battery Status:"
<#+-----------------------------------------------------+
| BatterStatus Values |
|Other (1) The battery is discharging. |
|Unknown (2) The system has access to AC so no |
| battery is being discharged. However, |
| the battery is not necessarily charging.|
|Fully Charged (3) |
|Low (4) |
|Critical (5) |
|Charging (6) |
|Charging and High (7) |
|Charging and Low (8) |
|Charging and Critical (9) |
|Undefined (10) |
|Partially Charged (11) |
+-----------------------------------------------------|#>
$GWArgs = #{ Class = "Win32_Battery"
ComputerName = "LocalHost"
}
$MyBattery = Get-CIMInstance #GWArgs
If ($Null -eq $MyBattery) {
$Message = "No Battery Present"
}
Else {
$BatteryRemaining = [Int]$MyBattery.EstimatedChargeRemaining
if(($BatteryRemaining -lt 30) -and
$($MyBattery.BatteryStatus) -eq 1) {
$Message = "Battery Low...Please Charge Me!"
}
Elseif(($BatteryRemaining -gt 90) -and
$($MyBattery.BatteryStatus) -ne 1) {
$Message =
"Battery CHARGED above 90%...Please Unplug Me!"
}
} #End Else
if($Message -ne "") {
$Null = & $StatusMsg
}
<#
+----------------------------------------------------------+
| Notes: |
| 1. To call as a scheduled task do the following in the |
| Action Pane |
| A. Action: Start a Program |
| B. Program/script: powershell.exe |
| D. Set the Trigger run At Logon and then repeat |
| every few minutes. |
+----------------------------------------------------------+
#>
If you want to use Toast msgs. just replace that logic where I have my $StatusMgs lines.

Objectify the results of Qwinsta

I am trying to write a script that will give me back as an object the results from qwinsta.
The code of my script is this:
function Get-QWinsta {
$queryResults = (qwinsta /Server:$ENV:COMPUTERNAME | ForEach-Object { ( ( $_.Trim() -replace "\s+",",") ) } | ConvertFrom-Csv)
$queryResults | ForEach-Object { if ( $_.SESSIONNAME -match 'da-' ) {
$_.USERNAME = $_.SESSIONNAME; $_.SESSIONNAME = $null; $_.STATE = $_.ID; $_.ID = $null
}
}
$RDPSESSIONS = $queryResults | ForEach-Object {
[PSCustomObject]#{
UserName = if ( $_.USERNAME -match '\d' ) { $_.USERNAME = $null } else { $_.USERNAME }
SessionName = if ( $_.SESSIONNAME -match 'services|console' ) { $_.SESSIONNAME = $null } else { $_.SESSIONNAME }
SessionID = $_.ID
SessionState = if ( $_.ID -match 'Disc' ) { $_.STATE = 'Disconnected' } else { $_.STATE }
}
}
return $RDPSESSIONS
}
and the output is this:
UserName SessionName SessionID SessionState
-------- ----------- --------- ------------
Disc
Conn
Admin01 Disc
Admin02 rdp-tcp#41 4 Active
rdp-tcp Listen
However the above is not a real object and what I would really want to have as output is something like this:
UserName SessionName SessionID SessionState
-------- ----------- --------- ------------
Admin01 Disc
Admin02 rdp-tcp#41 4 Active
Plus if I could something like this:
> $user1 = (Get-Qwinsta).UserName
> Write-Output $user1
> Admin01
that would be a bonus.
I have read all the similar post here and everywhere on the internet and none of them worked perfectly fine or did what I want to achieve.
You can get the qwinsta results as custom objects like this:
function Get-QWinsta
{
param ($ComputerName = "$env:COMPUTERNAME")
qwinsta /server:$ComputerName |
ForEach-Object {$_ -replace "\s{2,18}",","} |
ConvertFrom-Csv
}
> Get-QWinsta -ComputerName 'Server1'
This gives a custom object for each entry in the output:
SESSIONNAME : services
USERNAME :
ID : 0
STATE : Disc
TYPE :
DEVICE :
SESSIONNAME : console
USERNAME :
ID : 1
STATE : Conn
TYPE :
DEVICE :
SESSIONNAME : session1
USERNAME : User1
ID : 23
STATE : Active
TYPE : wdica
DEVICE :
SESSIONNAME : session2
USERNAME : User2
ID : 25
STATE : Active
TYPE : wdica
DEVICE :
Which can be manipulated like other objects. For example, shown in a table:
> Get-QWinsta -ComputerName 'Server1' | Format-Table -Autosize
SESSIONNAME USERNAME ID STATE TYPE DEVICE
----------- -------- -- ----- ---- -------
services 0 Disc
console 1 Conn
session1 User1 23 Active wdica
session2 User2 25 Active wdica
session3 User3 41 Active wdica
Or, output just specific properties:
> (Get-QWinsta -ComputerName 'Server1').UserName
User1
User2
User3

PowerShell: Iterating Multiple Variables not working as expected

I am trying to iterate over an array $dailyTasks to find 'Blank' i.e. '' values in the EmployeeName column and inject names from another array into those empty values.
Example of what the array looks like before the for loop starts:
| Task | EmployeeName | EmployeeName2 |
|-------|--------------|---------------|
| Task1 | | |
| Task2 | Person Y | |
| Task3 | | |
| Task4 | Person Z | Person X |
This is my for loop code that produces an undesired result. $randomisedUsers is an Object[]
$randomisedUsers | Group-Object { $_ -in ($randomisedUsers | Select-Object -Last 2) } | ForEach-Object {
if ($_.Name -eq 'True') {
for ($i = 0; $i -lt $dailyTasks.Count; $i++) {
if ($dailyTasks[$i].Task -eq 'Task4') {
$dailyTasks[$i].EmployeeName = $_.Group.EmployeeName[0]
$dailyTasks[$i].EmployeeName2 = $_.Group.EmployeeName[1]
}
}
} else {
for ($i = 0; $i -lt $dailyTasks.Count; $i++) {
if ($dailyTasks[$i].EmployeeName -eq '') {
if ($_.Count -gt '1') {
for ($x = 0; $x -lt $_.Group.EmployeeName.Count; $x++) {
$dailyTasks[$i].EmployeeName = $_.Group.EmployeeName[$x]
}
} else {
$dailyTasks[$i].EmployeeName = $_.Group.EmployeeName
}
}
}
}
}
Result:
| Task | EmployeeName | EmployeeName2 |
|-------|--------------|---------------|
| Task1 | Person A | |
| Task2 | Person Y | |
| Task3 | Person A | |
| Task4 | Person Z | Person X |
The problem here is that $_.Group.EmployeeName contains two objects but for whatever reason the result table doesnt populate Person B in the array:
$_.Group.EmployeeName
{Person A, Person B}
The desired result in this case is:
| Task | EmployeeName | EmployeeName2 |
|-------|--------------|---------------|
| Task1 | Person A | |
| Task2 | Person Y | |
| Task3 | Person B | |
| Task4 | Person Z | Person X |
Im not completely sure where im going wrong in my for loops and i've been stuck on this for a while...
TIA
I would personally use something like this:
$csv = #'
Task,EmployeeName,EmployeeName2
Task1,,
Task2,Person Y,
Task3,,
Task4,Person Z,Person X
'# | ConvertFrom-Csv
$fillEmployees = [System.Collections.ArrayList]#(
'Person A'
'Person B'
)
foreach($line in $csv)
{
if([string]::IsNullOrWhiteSpace($line.EmployeeName))
{
$line.EmployeeName = $fillEmployees[0]
$fillEmployees.RemoveAt(0)
}
}
The flow is quite simple, if the loop finds a value in EmployeeName that is null or has white spaces it will replace that value with the index 0 of $fillEmployees and then remove that index 0 from the list.
It's hard to tell what you're trying to accomplish with your code, but if you have an array of the type System.Array filled with random names which will be used to fill this empty values on EmployeeName you can convert that Array to an ArrayList which will allow you to use the .RemoveAt(..) method:
PS /> $fillEmployees = 0..10 | ForEach-Object {"Employee {0}" -f [char](Get-Random -Minimum 65 -Maximum 90)}
PS /> $fillEmployees
Employee J
Employee S
Employee D
Employee P
Employee O
Employee E
Employee M
Employee K
Employee R
Employee F
Employee A
PS /> $fillEmployees.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Attempting to Remove an item from an Array would result in the following:
PS /> $fillEmployees.RemoveAt(0)
Exception calling "RemoveAt" with "1" argument(s): "Collection was of a fixed size."
At line:1 char:1
...
...
However if convert it to an ArrayList (not convert it but copy it):
PS /> $fillEmployees = [System.Collections.ArrayList]$fillEmployees
PS /> $fillEmployees.RemoveAt(0)

Powershell: Merge multiple lines into one

I have a .csv file which looks like:
employeenumber;phone;mobile;fax;userid;Email
99999991;+1324569991;+234569991;+5234569991;user01;user1#domain.com
99999992;+1234569992;+234569992;;user02;user2#domain.com
99999993;+1234569993;+234569993;;user03;user3#domain.com
99999993;+12345699933;;;user03;user3#domain.com
99999993;;;+5234569993;user03;user3#domain.com
99999994;+1234569994;;;user04;user4#domain.com
As you can see there are different employeenumbers and some lines with the same employeenumber.
Is there any way to merge the lines with the same employeenumber in powershell?
Similar Output:
employeenumber;phone;mobile;fax;userid;Email
99999991;+1324569991;+234569991;+5234569991;user01;user1#domain.com
99999992;+1234569992;+234569992;;user2;user2#domain.com
99999993;+1234569993 / +12345699933;+234569993;+5234569993;user03;user3#domain.com
99999994;+1234569994;;;user04;user4#domain.com
Thank you
I've taken a shot at it. I believe my answer is easier to read than Mjolinor's.
I group the entries from the CSV into either $singletons or $duplicates, based on using the Group-Object command. Then, I pipe through the $duplicates and merge the records found in either the phone,mobile, or fax fields, using a '/' character as you've indicated.
#$csv = get-content .\CSVNeedstoMerge.csv
$csvValues = $csv | ConvertFrom-Csv -Delimiter ';'
$duplicates = $csvValues | group-object EmployeeNumber | ? Count -gt 1
$objs = New-Object System.Collections.ArrayList
$singletons = $csvValues | group-object EmployeeNumber | ? Count -eq 1 | % {$objs.Add($_.Group)}
ForEach ($duplicate in $duplicates){
$objs.Add([pscustomobject]#{employeenumber=($duplicate.Group.employeenumber | select -Unique) -as [int];
phone=($duplicate.Group.phone | ? Length -gt 0) -join '/';
mobile=($duplicate.Group.mobile| ? Length -gt 0) -join '/';
fax=($duplicate.Group.fax | ? Length -gt 0) -join '/';
userid = $duplicate.Group.userid | select -Unique
email= $duplicate.Group.email | select -Unique })
}
$objs | Sort EmployeeNumber
I'll give that a shot:
(#'
employeenumber;phone;mobile;fax;userid;Email
99999991;+1324569991;+234569991;+5234569991;user01;user1#domain.com
99999992;+1234569992;+234569992;;user02;user2#domain.com
99999993;+1234569993;+234569993;;user03;user3#domain.com
99999993;+12345699933;;;user03;user3#domain.com
99999993;;;+5234569993;user03;user3#domain.com
99999994;+1234569994;;;user04;user4#domain.com
'#).split("`n") |
foreach {$_.trim()} | sc test.csv
$ht = #{}
$props = (Get-Content test.csv -TotalCount 1).split(';')
import-csv test.csv -Delimiter ';' |
foreach {
if ( $ht.ContainsKey($_.employeenumber) )
{
foreach ($prop in $props )
{
if ($_.$prop )
{$ht[$_.employeenumber].$prop = $_.$prop }
}
}
else { $ht[$_.employeenumber] = $_ }
}
$ht.values | sort employeenumber
employeenumber : 99999991
phone : +1324569991
mobile : +234569991
fax : +5234569991
userid : user01
Email : user1#domain.com
employeenumber : 99999992
phone : +1234569992
mobile : +234569992
fax :
userid : user02
Email : user2#domain.com
employeenumber : 99999993
phone : +12345699933
mobile : +234569993
fax : +5234569993
userid : user03
Email : user3#domain.com
employeenumber : 99999994
phone : +1234569994
mobile :
fax :
userid : user04
Email : user4#domain.com

Cannot execute same powershell function twice, gives error

I'm fairly new to powershell and I'm basically writing a script which performs a join on several .csv files based on a primary column. I am using the Join-Collections script from here: http://poshcode.org/1461
As I need to combine 5 .csv files, I need to run this function 4 times.
On the first run, it works fine, but then trying to run the function again gives 'No object specified to the cmd-let' errors.
In trying to debug, I've literally copy-and-pasted the line and only changed the variable name to make a new variable.
I must be doing something fundamentally wrong...
$SumFile = "VMSummary.csv"
$MemFile = "VMMemory.csv"
$ProcFile = "VMProcessor.csv"
$OSFile = "VMOS.csv"
$NicFile = "VMNics.csv"
$SumFileCSV = Import-Csv $SumFile | Select VMElementName,GuestOS,Heartbeat,MemoryUsage,IpAddress
$MemFileCSV = Import-Csv $MemFile | Select VMElementName,Reservation
$ProcFileCSV = Import-Csv $ProcFile
$OSFileCSV = Import-Csv $OSFile
$NicFileCSV = Import-Csv $NicFile
$JoinColumn = "VMElementName"
function Join-Collections {
PARAM(
$FirstCollection
, [string]$FirstJoinColumn
, $SecondCollection
, [string]$SecondJoinColumn=$FirstJoinColumn
)
PROCESS {
$ErrorActionPreference = "Inquire"
foreach($first in $FirstCollection) {
$SecondCollection | Where{ $_."$SecondJoinColumn" -eq $first."$FirstJoinColumn" } | Join-Object $first
}
}
BEGIN {
function Join-Object {
Param(
[Parameter(Position=0)]
$First
,
[Parameter(ValueFromPipeline=$true)]
$Second
)
BEGIN {
[string[]] $p1 = $First | gm -type Properties | select -expand Name
}
Process {
$Output = $First | Select $p1
foreach($p in $Second | gm -type Properties | Where { $p1 -notcontains $_.Name } | select -expand Name) {
Add-Member -in $Output -type NoteProperty -name $p -value $Second."$p"
}
$Output
}
}
}
}
$Temp = Join-Collections $SumFileCSV $JoinColumn $MemFileCSV $JoinColumn
$Temp
##BREAKS HERE
$Temp2 = Join-Collections $SumFileCSV $JoinColumn $MemFileCSV $JoinColumn
UPDATE
It gives the following error:
No object has been specified to the get-member cmdlet
+ foreach($p) in $Second | gm <<<< -type Properties | Where { $p1 -notcontains $_.Name } | select -expand Name)
The csv data is pretty straight forward. When I print out $Temp just before it breaks, it spits out:
GuestOS : Windows Server (R) 2008 Standard
Heartbeat : OK
IpAddress : 192.168.48.92
MemoryUsage : 1024
VMElementName : VM015
Reservation : 1024
GuestOS : Windows Server (R) 2008 Standard
Heartbeat : OK
IpAddress : 192.168.48.151
MemoryUsage : 1028
VMElementName : VM053
Reservation : 1028
GuestOS : Windows Server (R) 2008 Standard
Heartbeat : OK
IpAddress : 192.168.48.214
MemoryUsage : 3084
VMElementName : VM065
Reservation : 3084
GuestOS :
Heartbeat :
IpAddress :
MemoryUsage :
VMElementName : VM074
Reservation : 1024
GuestOS : Windows Server 2008 R2 Standard
Heartbeat : OK
IpAddress : 192.168.48.32
MemoryUsage : 3072
VMElementName : VM088
Reservation : 3072
GuestOS : Windows Server (R) 2008 Enterprise
Heartbeat : OK
IpAddress : 192.168.48.81
MemoryUsage : 3084
VMElementName : VM090
Reservation : 3084
GuestOS : Windows Server 2008 R2 Enterprise
Heartbeat : OK
IpAddress : 192.168.48.82
MemoryUsage : 5120
VMElementName : VM106
Reservation : 5120
The rest of the .csv data is the same sort of stuff - just stats on different servers.
Ideally what I want to do is this :
$Temp = Join-Collections $SumFileCSV $JoinColumn $MemFileCSV $JoinColumn
$Temp = Join-Collections $Temp $JoinColumn $ProcFileCSV $JoinColumn
$Temp = Join-Collections $Temp $JoinColumn $OSFileCSV $JoinColumn
$Temp = Join-Collections $Temp $JoinColumn $NicFileCSV $JoinColumn | Export-Csv "VMJoined.csv" -NoTypeInformation -UseCulture
This code works fine on Powershell v3 CTP 2 (which is probably what #manojlds is using). In Powershell V2 however the parameter $second of the Join-Object function is not bound when invoking Join-Collections the second time. This can be easily verified by adding the following line to the process block inside the Join-Object function:
$psboundparameters | out-host
You will notice that when invoking Join-Collections for the first time both parameters (of Join-Object are bound, however the second time $second is no longer bound.
It is unclear what is causing this behaviour, but since it seems to be working in Powershell V3 I'm guessing it's a bug.
To make the function work in Powershell V2 one could explicitly bind the parameters by replacing this line:
$SecondCollection | Where{ $_."$SecondJoinColumn" -eq $first."$FirstJoinColumn" } | Join-Object $first
by this line:
$SecondCollection | Where{ $_."$SecondJoinColumn" -eq $first."$FirstJoinColumn" } | %{Join-Object -first $first -second $_}