0

I am trying to build a report file collecting data from various sources. I have built a reporting structure like this:

$Data = import-csv "some CSV FILE"
<#
csv file must look like this
hostname,IP
server1,192.168.1.20
#>

Then I am building an array object, prepopulated with "initial values", and I attach it to my $data variable

$Ids = ('7.1.1.1','7.1.1.2')
$CheckObj= @()
foreach ($id in $IDs) {
    $row = "" | Select-Object CheckID,CheckData,CheckDataRaw
    $row.CheckID = $id
    $row.CheckData = "NotChecked"
    $CheckObj+= $row
    }


$Data = $Data | Select *,CheckData

$data | % {$_.CheckData = $CheckObj}

The resulting object is:

hostname  : server1
ip        : 192.168.1.20
CheckData : {@{CheckID=7.1.1.1; CheckData=NotChecked; CheckDataRaw=}, 
            @{CheckID=7.1.1.2; CheckData=NotChecked; CheckDataRaw=}}

All is well until I want to do this:

$FinalReport = $data | Select-Object -Property * -ExpandProperty Checkdata

I get all these errors, which let's say I can ignore...

Select-Object : The property cannot be processed because the property 
"CheckData" already exists.
At line:1 char:24
+ ... lReport = $data | Select-Object -Property * -ExpandProperty Checkdata
+                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (@{hostname=serv...ystem.Objec 
   t[]}:PSObject) [Select-Object], PSArgumentException
    + FullyQualifiedErrorId : AlreadyExistingUserSpecifiedPropertyExpand,Micro 
   soft.PowerShell.Commands.SelectObjectCommand

BUT, an entire set of other variable gets altered, like:

$data | fl


hostname  : server1
ip        : 192.168.1.1
CheckData : {@{CheckID=7.1.1.1; CheckData=NotChecked; CheckDataRaw=; 
            hostname=server1; ip=192.168.1.1}, @{CheckID=7.1.1.2; 
            CheckData=NotChecked; CheckDataRaw=; hostname=server1; 
            ip=192.168.1.1}}

aswell as the $CheckObj variable

$CheckObj


CheckID      : 7.1.1.1
CheckData    : NotChecked
CheckDataRaw : 
hostname     : server1
ip           : 192.168.1.1

CheckID      : 7.1.1.2
CheckData    : NotChecked
CheckDataRaw : 
hostname     : server1
ip           : 192.168.1.1

This is totally unintended on my side... Can someone clarify what I am doing wrong?

I am using powershell 5.0 on Windows 7. All testing was done using powershell_ise, and I didn't change any of the powershell defaults

My expected result would be for the $Final Report variable to contain the expanded content, not all the variables I used in the process...

IonutN
  • 91
  • 1
  • 10
  • I think issue is coming from the fact that you use CheckData for storing collection in $data variable (probably as a column name in csv file) and at the same time using it as string variable (e.g. 'NotChecked') in objects stored in CheckData variable. It's probably better if you change your code $row.CheckData to something like $row.CheckStatus – Martin Lhotsky Feb 08 '17 at 13:25
  • Hi,The csv data, only has 2 rows, hostname and IP. Also i tried to give my data variable another property name like:$Data = $Data | Select *,CheckData2, keeping other variable names identical. It still behaves in the same way described above. – IonutN Feb 08 '17 at 13:34
  • After renaming $Data = $Data | Select *,CheckData2 you did you also change $data | % {$_.CheckData2 = $CheckObj} and created all objects from scratch? – Martin Lhotsky Feb 08 '17 at 13:50
  • Yes I did here's a pastebin output of the whole thing. I even tried in normal powershell, instead of powershell_ise, same result http://pastebin.com/NMpzmLDL – IonutN Feb 08 '17 at 14:32

1 Answers1

1

It seems, after a bit more digging I understood, to some extent why this is occurring.

I am using simple $b = $a assignments, which appear to be a form of shallow copy. So any change in $b also impacts object $a and vice-versa.

For my purpose I need distinct copies of the data, it seems the solution is to do a deep copy, similar to the solution of this post: PowerShell copy an array completely

So the working code, which gives me the desired result would be:

    Function Copy-Object ($Source,[switch]$DeepCopy) {
        # Serialize and Deserialize data using BinaryFormatter
        if ($DeepCopy) {
            $ms = New-Object System.IO.MemoryStream
            $bf = New-Object System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
            $bf.Serialize($ms, $Source)
            $ms.Position = 0

            #Deep copied data
            $Target = $bf.Deserialize($ms)
            $ms.Close()
            Write-Output $Target
            }
        Else {
            Write-Output $Source
            }
        }


$Data = "" | select hostname,IP
$data.Hostname = "server1"
$data.IP = "192.168.1.10"

$Ids = ('7.1.1.1','7.1.1.2')
$CheckObj= @()
foreach ($id in $IDs) {
    $row = "" | Select-Object CheckID,CheckData,CheckDataRaw
    $row.CheckID = $id
    $row.CheckData = "NotChecked"
    $CheckObj += $row
    }


$Data = Copy-Object -source $Data -DeepCopy | Select *,CheckData2

$Data | % {$_.CheckData2 = Copy-Object -source $CheckObj -DeepCopy}

$FinalReport = Copy-Object -source $Data -DeepCopy | Select-Object -Property hostname,IP -ExpandProperty Checkdata2
$FinalReport  | ft

output being:

CheckID CheckData  CheckDataRaw hostname IP          
------- ---------  ------------ -------- --          
7.1.1.1 NotChecked              server1  192.168.1.10
7.1.1.2 NotChecked              server1  192.168.1.10
Community
  • 1
  • 1
IonutN
  • 91
  • 1
  • 10