VMware Cloud Community
HywelBurris
Enthusiast
Enthusiast
Jump to solution

Convert string back to system object when importing from CSV

Apologies all, another newbie question,

I am trying to import a list of firewall rules in order to harden the ESXi hosts. I have copied out the rules in the format below, modified them in excel and saved to a csv file.

I created a function to copy them from a source esxi host and copy them to a destination host. I would now like to do this differently and copy in from a CSV (as we can use this as documentation for each rule) in the same format. The issue I am getting is for the "AllowedIPAddresses" column, this was originally a system.object in the output from powercli but obviously a string when I import it back in.

Ruleset AllowedIPAddresses Enabled
activeDirectoryAll {AA.BB.28.1,AA.BB.28.2,AA.BB.124.1,AA.BB.124.2} TRUE
CIMHttpServer {AA.BB.134.77} TRUE
CIMHttpsServer {AA.BB.134.77} TRUE
CIMSLP {AA.BB.21.128/26} TRUE
cmmds {All} FALSE
dhcp {All} FALSE
DHCPv6 {All} FALSE
dns {AA.BB.28.1,AA.BB.28.2,AA.BB.124.1,AA.BB.124.2} TRUE
DVFilter {All} FALSE
DVSSync {AA.BB.136.0/24} TRUE
faultTolerance {AA.BB.136.0/24} TRUE
fdm {AA.BB.136.0/24} TRUE
ftpClient {All} FALSE
gdbserver {All} FALSE
HBR {All} FALSE
httpClient {AA.BB.134.78} TRUE
IKED {All} FALSE
ipfam {All} FALSE
iSCSI {All} FALSE
N1KV-Distributed-NetFlow {All} TRUE
N1KV-L3-Ctrl {AA.BB.141.1,AA.BB.136.0/24} TRUE
N1KV-L3-VNService {AA.BB.141.1} TRUE
NFC {AA.BB.134.77,AA.BB.136.0/24} TRUE
nfsClient {All} FALSE
ntpClient {AA.BB.31.123,AA.BB.127.123} TRUE
rabbitmqproxy {All} FALSE
rdt {All} FALSE
remoteSerialPort {All} FALSE
snmp {All} FALSE
sshClient {All} FALSE
sshServer {AA.BB.134.77,AA.BB.98.41,AA.BB.2.41,AA.BB.21.128/26} TRUE
syslog {AA.71.AA.10} TRUE
updateManager {AA.BB.134.78} TRUE
vMotion {All} TRUE
vprobeServer {All} FALSE
vpxHeartbeats {AA.BB.134.77} TRUE
vsanvp {AA.BB.134.77} TRUE
vSPC {All} FALSE
vSphereClient {AA.BB.134.77,AA.BB.134.78,AA.BB.21.128/26} TRUE
webAccess {All} FALSE
WOL {All} TRUE

My question is how to I create the "AllowedIPAddresses" as a system.object when I import the {IP1, IP2, IP3} back in and I can compare and do foreach loops again, against the destination hosts settings.

The function is below. I am sure there is a better way of doing what I am doing but I understand this way Smiley Wink

# $SrcVIHost = 'Host1'

$DstVIHost = 'Host2'

$vCenterServer = '127.0.0.1'

$applychanges = 'yes'

$SrcFWFile = 'Rules.csv'

Connect-VIServer -Server $vCenterServer | Out-Null

Function Copy-FwSettings  {

    param

    (

        [Object]

        $CurrentSetting

    )

#    *** old code to copy settings from host ***

#    $SrcEsxcli = Get-EsxCli -VMHost $SrcVIHost

#    if($SrcEsxcli -ne $null){

#        $Srcfwenabled = $SrcEsxcli.network.firewall.ruleset.list() | Where-Object { $_.Name -eq $CurrentSetting }  | Select-Object Name, Enabled

#        $SrcfwIpList = $Srcesxcli.network.firewall.ruleset.allowedip.list($CurrentSetting) | Select-Object Ruleset, AllowedIPAddresses   

#    }

#   Copy settings from CSV file

    $Srcdata  | Select-Object Ruleset, IPAllowed, Enabled

    if($Srcdata -ne $null){

        $Srcfwenabled = $Srcdata  | where-object { $_.Ruleset -eq $CurrentSetting.ruleset } | Select-Object Ruleset, Enabled

        $SrcfwIpList = $Srcdata | where-object { $_.Ruleset -eq $CurrentSetting.ruleset } |Select-Object Ruleset, IPAllowedIPAddresses

    }

#   Get destination host current settings.

    $DstEsxcli = Get-EsxCli -VMHost $DstVIHost

    if($DstEsxcli -ne $null){

        $Dstfwenabled = $DstEsxcli.network.firewall.ruleset.list() | Where-Object { $_.Name -eq $CurrentSetting }  | Select-Object Name, Enabled

        $DstfwIpList = $Dstesxcli.network.firewall.ruleset.allowedip.list($CurrentSetting) | Select-Object Ruleset, AllowedIPAddresses

    }

#   Compare Firewall rulesets for a  difference

    $diff = Compare-Object -DifferenceObject $SrcfwIpList -ReferenceObject $DstfwIpList -Property AllowedIpAddresses

    #Checking if FW rule $CurrentSetting should be enabled for all IP Addresses...

    If (($Srcfwenabled.enabled -eq $Dstfwenabled.enabled) -and ($Srcfwenabled.enabled -eq $true) -and ($SrcfwIpList.AllowedIPAddresses -eq 'All') -and ($DestfwIpList.AllowedIPAddresses -eq 'All')) {

        write-host "The $CurrentSetting rule is already enabled for all IP Addresses"  -ForegroundColor Green

    }

    #Checking if FW rule $CurrentSetting is disabled on both systems...

    elseif (($Srcfwenabled.enabled -eq $false) -and ($Dstfwenabled.enabled -eq $false)) {

        Write-host "The rule $CurrentSetting is already disabled"

    }

    #Write-Host "Checking if FW rule $CurrentSetting should be disabled on the destination Host...

    elseif (($Srcfwenabled.enabled -eq $false) -and ($Dstfwenabled.enabled -eq $true)) {

        write-host "The $CurrentSetting needs to be disabled on the destination host"

        if ($ApplyChanges -eq 'Yes') {

            $DstEsxCli.network.firewall.ruleset.set($true, $false, $CurrentSetting) # Sets “AllowedAll” to $true, “Enabled” to $false on rule set defined by function

            $DstEsxcli.network.firewall.refresh() # Reloads the firewall rules

        }

        else {

            write-Host 'Changes Disabled not Disabling firewall Rule' -foregroundcolor 'Yellow'

        }

    }

    #Checking if FW rule $CurrentSetting should be enabled on the destination Host and allow all IP's...

    elseif (($Srcfwenabled.enabled -eq $true) -and ($Dstfwenabled.enabled -eq $false)) {

        write-host "The $CurrentSetting needs to be enabled on the destination host and allow all IP Addresses"

        if ($ApplyChanges -eq 'Yes') {

            $DstEsxCli.network.firewall.ruleset.set($true, $true, $CurrentSetting) # Sets “AllowedAll” to $true, “Enabled” to $true on rule set defined by function

            $DstEsxcli.network.firewall.refresh() # Reloads the firewall rules

        }

        else {

            write-Host 'Changes Disabled not enabling firewall Rule' -foregroundcolor 'Yellow'

        }

    }

  # Checking if FW rule $CurrentSetting should be enabled on the destination Host and allow specific IP's...

    elseif (($Srcfwenabled.enabled -eq $true) -and ($Srcfwenabled.enabled -eq $true) -and ($SrcfwIpList.AllowedIPAddresses -ne 'All')) {

        if ($DstfwIpList.AllowedIPAddresses -eq 'All') {

            write-host "The $CurrentSetting needs to be enabled on the destination host and allow specific IP Addresses"

            if ($ApplyChanges -eq 'Yes') {

                Write-Host 'Setting firewall ruleset'

                $DstEsxCli.network.firewall.ruleset.set($false, $true, $CurrentSetting) # Sets “AllowedAll” to $false, “Enabled” to $true on rule set defined by function

                $DstEsxcli.network.firewall.refresh() # Reloads the firewall rules

            }

            else {

                Write-Host "Changes disabled not changing Firewall config for $CurrentSetting"  -foregroundcolor 'Yellow'

            }

        }

        else {

            write-host "The $CurrentSetting is already enabled on the destination host and allow specific IP Addresses" -ForegroundColor 'Green'

        }

        If ($diff -eq $null) {

            Write-Host "The rule $CurrentSetting is enabled and configured correctly and the Allowed IP's are already correct" -ForegroundColor 'Green'

        }

        else {

            if ($ApplyChanges -eq 'Yes') {

                # Removing Old IP Addresses.

                If ($DstfwIpList.AllowedIPAddresses -ne 'All'){

                    foreach ($DIP in $DstfwIpList.AllowedIPAddresses) {

                        $DstEsxCli.network.firewall.ruleset.allowedip.remove("$DIP", "$CurrentSetting")

                        Write-Host "$CurrentSetting Allowed IP Addresses Changed. Removed $DIP"

                    }

                }

                # Adding IP Addresses.

                Write-Host 'Adding the correct IP Addresses'

                foreach ($SIP in $SrcfwIpList.AllowedIPAddresses) {

                    $DstEsxCli.network.firewall.ruleset.allowedip.add("$SIP", "$CurrentSetting")

                    Write-Host "$CurrentSetting Allowed IP Addresses Changed. Added $SIP"

                }

            }

            else {

                write-Host 'Changes Disabled not applying' -foregroundcolor 'Yellow'

            }

        $DstEsxcli.network.firewall.refresh() # Reloads the firewall rules

        }

    }

    else {

        Write-Host 'There was an issue with FW configuration' -ForegroundColor 'Red'

    }

}

$Srcdata = import-csv -path $SrcFWFile

Foreach ($CurrentSetting in $Scrdata) {

    Copy-FwSettings $CurrentSetting.Ruleset

    }

Many thanks for any ideas or answers to give me some clues.

Buzz

1 Solution

Accepted Solutions
ccalvetTCC
Enthusiast
Enthusiast
Jump to solution

Back to the start
Is there a specific reason to use ESXCLI command instead of the API?

Please check the HostFirewallSystem

In general it is better to use the API and use esxcli only if something is not available via the API.

If you want to continue with esxcli

$DstEsxCli.network.firewall.ruleset.set($true, $false, $CurrentSetting)

$esxcli.network.firewall.ruleset.set($allowedall,$enabled,$rulesetid)

.PARAMETER allowedall

Set to true to allowed all ip, set to false to use allowed ip list.

.PARAMETER enabled

Set to true to enable ruleset, set to false to disable it.

.PARAMETER rulesetid

The label of the ruleset.

[System.Nullable[boolean]]$allowedall,

[System.Nullable[boolean]]$enabled,

[string]$rulesetid,

$DstEsxCli.network.firewall.ruleset.allowedip.remove("$DIP", "$CurrentSetting")

$esxcli.network.firewall.ruleset.allowedip.remove($ipaddress,$rulesetid)

.PARAMETER ipaddress

Allowed ip address/range for the ruleset.

.PARAMETER rulesetid

The label of the ruleset.

[string]$ipaddress,

[string]$rulesetid,

$DstEsxCli.network.firewall.ruleset.allowedip.add("$SIP", "$CurrentSetting")

$esxcli.network.firewall.ruleset.allowedip.add($ipaddress,$rulesetid)

.PARAMETER ipaddress

Allowed ip address/range for the ruleset.

.PARAMETER rulesetid

The label of the ruleset.

[string]$ipaddress,

[string]$rulesetid,

All parameters above have been extracted from get-esxli on steroids‌ and these functions have been generated from information directly obtained from get-esxcli for all namespaces.

The key point is that none of these functions require as a parameter an object of type:

TypeName: "Selected.VMware.VimAutomation.ViCore.Impl.V1.EsxCli.EsxCliObjectImpl"

So you don't need to convert back to a "Selected.VMware.VimAutomation.ViCore.Impl.V1.EsxCli.EsxCliObjectImpl" consequently the title of this topic is not relevant anymore.

And by the way this type of object will be returned for ANY get-esxcli command.

If you need to split your initial csv table in many lines (One for each IP) you can use

$MyTable = Import-csv "YourPath\firewall.csv" -Delimiter `t

$NewTable = $MyTable | foreach-object{

$MyRow = $_

($_.ALLowedIPAddresses -replace'[{}]','').split(",") | foreach-object{

            $Output = New-Object -Type PSObject -Prop ([ordered]@{

              'RuleSet'= $MyRow.RuleSet

              'ALLowedIPAddresses' = $_

              'Enabled' = $MyRow.Enabled

            })       

            Return $Output

}

}

$NewTable


The result is:

PowerCLI C:\> $NewTable

RuleSet                  ALLowedIPAddresses Enabled

-------                  ------------------ -------

activeDirectoryAll       AA.BB.28.1         TRUE

activeDirectoryAll       AA.BB.28.2         TRUE

activeDirectoryAll       AA.BB.124.1        TRUE

activeDirectoryAll       AA.BB.124.2        TRUE

CIMHttpServer            AA.BB.134.77       TRUE

CIMHttpsServer           AA.BB.134.77       TRUE

CIMSLP                   AA.BB.21.128/26    TRUE

cmmds                    All                FALSE

****

Fot the import i have used tab as a delimiter. (Tab was used in the example you have provided)

-replace'[{}]','

is used to remove the characters{}

.split(",")

As discussed earlier

If and only if "activeDirectoryAll" is the ruleset ID (I am not able to test) then you should be in position to do for example:

$NewTable | foreach-object {

$DstEsxCli.network.firewall.ruleset.allowedip.add($_.ALLowedIPAddresses, "$_.RuleSet")

}

Or if you just want an object with an array in "AllowedIPAddresses"

  $NewTable = $MyTable | foreach-object{

            $Output = New-Object -Type PSObject -Prop ([ordered]@{

              'RuleSet'= $_.RuleSet

              'ALLowedIPAddresses' =  ($_.ALLowedIPAddresses -replace'[{}]','').split(",")

              'Enabled' = $_.Enabled

            })         

            Return $Output

}

   $NewTable

$NewTable and $MyTable will look the same...

But

$MyTable.allowedIPAddresses

$NewTable.allowedIPAddresses

Will show that you have now an array within ALLowedIPAddresses and not a long string.

Blog: http://thecrazyconsultant.com/ | Twitter: @ccalvetTCC

View solution in original post

Reply
0 Kudos
5 Replies
ccalvetTCC
Enthusiast
Enthusiast
Jump to solution

"AllowedIPAddresses" as a system.object

Maybe the split function will help in that case (however maybe it will not create a system.object)

Using it on the AllowedIPAddresses with "," as a separator.

Blog: http://thecrazyconsultant.com/ | Twitter: @ccalvetTCC
HywelBurris
Enthusiast
Enthusiast
Jump to solution

Thanks for the reply I really appreciate it.

Your reply got me thinking. I don't know whether it matters if its a system.object or not, aren't they both arrays?

I have simplified what I am trying to do, by removing the full function, to its bare minimum. I **think** I need to somehow make the AllowedIPAddresses an array rather than string. this is basically what I am struggling with

$SrcFWFile = 'c:\temp\Rules.csv'

$Srcdata = import-csv -path $SrcFWFile 

# $Srcdata  | Select-Object Ruleset, AllowedIPAddresses , Enabled

    $Srcdata = import-csv -path $SrcFWFile

foreach ($currentsetting in $Srcdata) {

    if($Srcdata -ne $null){

        $Srcfwenabled = $Srcdata  | Where-Object { $_.Ruleset -eq $CurrentSetting.Ruleset }  | Select-Object Ruleset, Enabled

        $SrcfwIpList = $Srcdata | Where-Object { $_.Ruleset -eq $CurrentSetting.Ruleset }  | Select-Object Ruleset, AllowedIPAddresses

    }

    $type = $SrcfwIpList.AllowedIPAddresses

    $SrcfwIpList.Ruleset, $type.GetType().Name, $SrcfwIpList.AllowedIPAddresses

}

Reply
0 Kudos
HywelBurris
Enthusiast
Enthusiast
Jump to solution

I changed the code slightly to display the member types

# Load Windows PowerShell cmdlets for managing vSphere

Add-PsSnapin VMware.VimAutomation.Core -ea 'SilentlyContinue'

$DstVIHost = 'Host2'

$applychanges = 'yes'

$SrcFWFile = 'c:\temp\Rules.csv'

$vCenterServer = '127.0.0.1'

$applychanges = 'yes'

$CurrentSetting = 'sshServer'

Connect-VIServer -Server $vCenterServer | Out-Null

    $DstEsxcli = Get-EsxCli -VMHost $DstVIHost

    if($DstEsxcli -ne $null){

        $Dstfwenabled = $DstEsxcli.network.firewall.ruleset.list() | Where-Object { $_.Name -eq $CurrentSetting }  | Select-Object Name, Enabled

        $DstfwIpList = $Dstesxcli.network.firewall.ruleset.allowedip.list($CurrentSetting) | Select-Object Ruleset, AllowedIPAddresses

    }

$Srcdata = import-csv -path $SrcFWFile  

# $Srcdata  | Select-Object Ruleset, AllowedIPAddresses , Enabled

    $Srcdata = @(import-csv -path $SrcFWFile)

foreach ($currentsetting in $Srcdata) {

    if($Srcdata -ne $null){

        $Srcfwenabled = $Srcdata  | Where-Object { $_.Ruleset -eq $CurrentSetting.Ruleset }  | Select-Object Ruleset, Enabled

        $SrcfwIpList = $Srcdata | Where-Object { $_.Ruleset -eq $CurrentSetting.Ruleset }  | Select-Object Ruleset, AllowedIPAddresses

    }

}

    $SrcfwIpList | get-Member

    $DstfwIpList | Get-Member

This gives the output

   TypeName: Selected.System.Management.Automation.PSCustomObject

Name                             MemberType        Definition                           

----                                  ----------                 ----------                           

Equals                            Method                bool Equals(System.Object obj)       

GetHashCode                 Method                int GetHashCode()                    

GetType                         Method                type GetType()                       

ToString                         Method                string ToString()                    

AllowedIPAddresses       NoteProperty       System.String AllowedIPAddresses={All}

Ruleset                          NoteProperty       System.String Ruleset=WOL            

   TypeName: Selected.VMware.VimAutomation.ViCore.Impl.V1.EsxCli.EsxCliObjectImpl

Name                             MemberType       Definition                                       

----                                  ----------                ----------                                       

Equals                           Method               bool Equals(System.Object obj)                   

GetHashCode                 Method              int GetHashCode()                                

GetType                         Method               type GetType()                                   

ToString                         Method               string ToString()                                

AllowedIPAddresses       NoteProperty      System.Object[] AllowedIPAddresses=System.Object[]

Ruleset                          NoteProperty      System.String Ruleset=sshServer  

I am now fairly sure that I was partially correct with my original statement when I suggested import the "AllowedIPAddresses" as a system.object. Unfortunately, I am only a white belt at powershell and a little lost with regards to using split or another method to manipulate the string {IP1, IP2, IP3} and make them usable within the array.

Thanks

Reply
0 Kudos
ccalvetTCC
Enthusiast
Enthusiast
Jump to solution

Back to the start
Is there a specific reason to use ESXCLI command instead of the API?

Please check the HostFirewallSystem

In general it is better to use the API and use esxcli only if something is not available via the API.

If you want to continue with esxcli

$DstEsxCli.network.firewall.ruleset.set($true, $false, $CurrentSetting)

$esxcli.network.firewall.ruleset.set($allowedall,$enabled,$rulesetid)

.PARAMETER allowedall

Set to true to allowed all ip, set to false to use allowed ip list.

.PARAMETER enabled

Set to true to enable ruleset, set to false to disable it.

.PARAMETER rulesetid

The label of the ruleset.

[System.Nullable[boolean]]$allowedall,

[System.Nullable[boolean]]$enabled,

[string]$rulesetid,

$DstEsxCli.network.firewall.ruleset.allowedip.remove("$DIP", "$CurrentSetting")

$esxcli.network.firewall.ruleset.allowedip.remove($ipaddress,$rulesetid)

.PARAMETER ipaddress

Allowed ip address/range for the ruleset.

.PARAMETER rulesetid

The label of the ruleset.

[string]$ipaddress,

[string]$rulesetid,

$DstEsxCli.network.firewall.ruleset.allowedip.add("$SIP", "$CurrentSetting")

$esxcli.network.firewall.ruleset.allowedip.add($ipaddress,$rulesetid)

.PARAMETER ipaddress

Allowed ip address/range for the ruleset.

.PARAMETER rulesetid

The label of the ruleset.

[string]$ipaddress,

[string]$rulesetid,

All parameters above have been extracted from get-esxli on steroids‌ and these functions have been generated from information directly obtained from get-esxcli for all namespaces.

The key point is that none of these functions require as a parameter an object of type:

TypeName: "Selected.VMware.VimAutomation.ViCore.Impl.V1.EsxCli.EsxCliObjectImpl"

So you don't need to convert back to a "Selected.VMware.VimAutomation.ViCore.Impl.V1.EsxCli.EsxCliObjectImpl" consequently the title of this topic is not relevant anymore.

And by the way this type of object will be returned for ANY get-esxcli command.

If you need to split your initial csv table in many lines (One for each IP) you can use

$MyTable = Import-csv "YourPath\firewall.csv" -Delimiter `t

$NewTable = $MyTable | foreach-object{

$MyRow = $_

($_.ALLowedIPAddresses -replace'[{}]','').split(",") | foreach-object{

            $Output = New-Object -Type PSObject -Prop ([ordered]@{

              'RuleSet'= $MyRow.RuleSet

              'ALLowedIPAddresses' = $_

              'Enabled' = $MyRow.Enabled

            })       

            Return $Output

}

}

$NewTable


The result is:

PowerCLI C:\> $NewTable

RuleSet                  ALLowedIPAddresses Enabled

-------                  ------------------ -------

activeDirectoryAll       AA.BB.28.1         TRUE

activeDirectoryAll       AA.BB.28.2         TRUE

activeDirectoryAll       AA.BB.124.1        TRUE

activeDirectoryAll       AA.BB.124.2        TRUE

CIMHttpServer            AA.BB.134.77       TRUE

CIMHttpsServer           AA.BB.134.77       TRUE

CIMSLP                   AA.BB.21.128/26    TRUE

cmmds                    All                FALSE

****

Fot the import i have used tab as a delimiter. (Tab was used in the example you have provided)

-replace'[{}]','

is used to remove the characters{}

.split(",")

As discussed earlier

If and only if "activeDirectoryAll" is the ruleset ID (I am not able to test) then you should be in position to do for example:

$NewTable | foreach-object {

$DstEsxCli.network.firewall.ruleset.allowedip.add($_.ALLowedIPAddresses, "$_.RuleSet")

}

Or if you just want an object with an array in "AllowedIPAddresses"

  $NewTable = $MyTable | foreach-object{

            $Output = New-Object -Type PSObject -Prop ([ordered]@{

              'RuleSet'= $_.RuleSet

              'ALLowedIPAddresses' =  ($_.ALLowedIPAddresses -replace'[{}]','').split(",")

              'Enabled' = $_.Enabled

            })         

            Return $Output

}

   $NewTable

$NewTable and $MyTable will look the same...

But

$MyTable.allowedIPAddresses

$NewTable.allowedIPAddresses

Will show that you have now an array within ALLowedIPAddresses and not a long string.

Blog: http://thecrazyconsultant.com/ | Twitter: @ccalvetTCC
Reply
0 Kudos
HywelBurris
Enthusiast
Enthusiast
Jump to solution

Thanks very much helped me out a lot

Reply
0 Kudos