1

I have written powershell scirpt to generate IIS information to CSV.

$bindingip = Get-WmiObject -Namespace root\webadministration -Class sslbinding2 | Select-Object - 
Property PSComputerName,IPAddress
$sitedetails = Get-Website | Select-Object -Property Name,ID,State
$report = New-Object psobject
$report | Add-Member -MemberType NoteProperty -Name "Hostname" -Value $bindingip.PSComputerName
$report | Add-Member -MemberType NoteProperty -Name "IPAddress" -Value $bindingip.IPAddress
$report | Add-Member -MemberType NoteProperty -Name "Site Name" -Value $sitedetails.name
$report | Add-Member -MemberType NoteProperty -Name "ID" -Value $sitedetails.id
$report | Add-Member -MemberType NoteProperty -Name "State" -Value $sitedetails.state
$report | Export-Csv C:\content.csv -NoTypeInformation

Output of CSV:

Hostname         IPAddress        Site Name       ID               State
System.Object[]  System.Object[]  System.Object[] System.Object[]  System.Object[]

Do i need to add anything to the code to get exact output, Can anyone help on this.

mklement0
  • 382,024
  • 64
  • 607
  • 775
DKU
  • 77
  • 1
  • 7
  • 1
    Hmm, that's odd. Does it make any difference changing it to a `pscustomobject`? Also, you should start using the Get-Ciminstance cmdlets introduced in v3. Try adding `Out-String`. – Abraham Zinala May 29 '21 at 18:01
  • @AbrahamZinala I have tested with {pscustomobject} that result is same. – DKU May 29 '21 at 18:12
  • 2
    Looks like `$bindingZip` and `$sitedetails` possibly contain multiple objects to me. Have you tried printing the information to console before you create the PSObject? I think you probably meant to use `-ExpandProperty` both times you call `Select-Object` too rather than just `-Property`. – Ash May 29 '21 at 18:20
  • @Ash My bad, Yes I have updated the script accordingly. I need to executed this script against the multiple servers so I have added the Invoke-Command and few lines to the script. – DKU May 30 '21 at 18:40

2 Answers2

2

As Abraham and Ash pointed out in their comments, the values of the properties on your variables $bindingip and $sitedetails are an array instead of a string. This is why when you export the report you get the object type instead of it's actual value.

You could see this by doing for example this:

$bindingip.PSComputerName.GetType()

Which would return something like this:

IsPublic IsSerial Name        BaseType    
-------- -------- ----        --------    
True     True     Object[]    System.Array

However if you select just the first element on the array PSComputerName

$bindingip.PSComputerName[0].GetType()

You would see:

IsPublic IsSerial Name        BaseType     
-------- -------- ----        --------     
True     True     String      System.Object

A workaround for this, is to either convert the values to a multiline string by the use of Out-String or by joining the elements of the arrays with a delimiter i.e. -join '//'.

$bindingip = Get-WmiObject -Namespace root\webadministration -Class sslbinding2
$sitedetails = Get-Website

# Like this (thanks mklement0):
$report = [pscustomobject]@{
    Hostname = "$($bindingip.PSComputerName)"
    IPAddress = "$($bindingip.IPAddress)"
    'Site Name' = "$($sitedetails.name)"
    ID = "$($sitedetails.id)"
    State = "$($sitedetails.state)"
}

# Or like this:
$report = [pscustomobject]@{
    Hostname = ($bindingip.PSComputerName | Out-String).trim()
    IPAddress = ($bindingip.IPAddress | Out-String).trim()
    'Site Name' = ($sitedetails.name | Out-String).trim()
    ID = ($sitedetails.id | Out-String).trim()
    State = ($sitedetails.state | Out-String).trim()
}

# Or like this:
$report = [pscustomobject]@{
    Hostname = $bindingip.PSComputerName -join '//'
    IPAddress = $bindingip.IPAddress -join '//'
    'Site Name' = $sitedetails.name -join '//'
    ID = $sitedetails.id -join '//'
    State = $sitedetails.state -join '//'
}

$report | Export-Csv C:\content.csv -NoTypeInformation

Edit

This can also work, which is what I think mklement0 suggested. It will create a new object for each element on the values of the properties:

$compName = $bindingip.PSComputerName
$ipAddr = $bindingip.IPAddress
$name = $sitedetails.name
$id = $sitedetails.id
$state = $sitedetails.state

$top = ($compName.Count,$ipAddr.Count,$name.Count,$id.Count,$state.Count | Measure-Object -Maximum).Maximum

$report = for($i = 0;$i -lt $top;$i++)
{
    [pscustomobject]@{
        Hostname = $compName[$i]
        IPAddress = $ipAddr[$i]
        'Site Name' = $name[$i]
        ID = $id[$i]
        State = $state[$i]
}

$report | Export-Csv...
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • 1
    A more efficient way is to simply let string interpolation handle the array stringification, e.g. `"$($bindingip.PSComputerName)"`. As for building up a collection via a list: that works, and is certainly preferable to "appending" to arrays with `+=`, but note that simply treating the entire `for` loop as an expression is both more concise and more efficient (`$report = for (...) { ... }`) - see [this answer](https://stackoverflow.com/a/60708579/45375). (But +1). – mklement0 May 29 '21 at 19:12
  • 1
    @mklement0 thank you for the insight sir, your feedback is always on point. I edited my answer. – Santiago Squarzon May 29 '21 at 19:23
  • @SantiagoSquarzon Thank you. I have made few changes to the script accordingly, I am facing two issues with my script. When I exporting the content to the CSC the entire output is storing in One cell in the script. Is there any way to format the output to the each cell in the CSV. – DKU May 30 '21 at 18:37
  • @DKU the code from the last edit on my answer should do the trick. – Santiago Squarzon May 30 '21 at 18:44
  • @SantiagoSquarzon Thank You, I will test in my lab accordingly, I have modified the script to the run against the multiple servers, for that I have added Invoke-Command. The new requirement I am thinking is resolve the binding IP address and add in the same CSV For this I am using Resolve-DNSName $ipadd | select-object -property NameHost, I am unable to added the data to CSV each resolved hostname from the IP address. – DKU May 30 '21 at 19:24
1

In addition to Santiago's very thorough and excellent answer, it appears to me that we are just combining the objects of one array with another to produce all possible combinations. I might do something like the following to accomplish this.

$bindingip = @(
    [PSCustomObject]@{
        PSComputerName = 'Public1'
        IPAddress      = '192.168.0.1'
    },
    [PSCustomObject]@{
        PSComputerName = 'Public1'
        IPAddress      = '127.0.0.1'
    }
)

$siteDetails = @(
    [PSCustomObject]@{
        Name  = 'site 1'
        Id    = 'site1'
        State = 'up'
    },
    [PSCustomObject]@{
        Name  = 'site 2'
        Id    = 'site2'
        State = 'down'
    }
)    

$combined = foreach ($ip in $bindingip) {
    foreach ($details in $siteDetails) {
        $out = [ordered]@{}
        $ip.psobject.properties | ForEach-Object {
            $out[$_.Name] = $_.Value
        }
        $details.psobject.properties | ForEach-Object {
            $out[$_.Name] = $_.Value
        }

        [pscustomobject]$out
    }
}

$combined | Format-Table

Output

PSComputerName IPAddress   Name   Id    State
-------------- ---------   ----   --    -----
Public1        192.168.0.1 site 1 site1 up
Public1        192.168.0.1 site 2 site2 down
Public1        127.0.0.1   site 1 site1 up
Public1        127.0.0.1   site 2 site2 down

One might wrap this in a function for reusability

function Combine-ObjectsFromTwoArrays {
    param (
        [array]$array1,
        [array]$array2
    )

    foreach ($obj1 in $array1) {
        foreach ($obj2  in $array2) {
            $out = [ordered]@{}
            $obj1.psobject.properties | ForEach-Object {
                $out[$_.Name] = $_.Value
            }
            $obj2.psobject.properties | ForEach-Object {
                $out[$_.Name] = $_.Value
            }

            [pscustomobject]$out
        }
    }
}
Daniel
  • 4,792
  • 2
  • 7
  • 20