"Counting" in an arrays using powershell - arrays

Hi I'm trying to count number of arrow where two value are matched.
Here is how i put value in my array :
$obj | add-member -name "Site" -membertype Noteproperty -value $sitecode
$obj | add-member -name "Location" -membertype Noteproperty -value $location
$obj | add-member -name "SwitchName" -membertype Noteproperty -value $swname
$obj | add-member -name "MacAddress" -membertype Noteproperty -value $mac
$obj | add-member -name "Interface" -membertype Noteproperty -value $eth
$obj | add-member -name "Macvendor" -membertype Noteproperty -value ""
$obj | add-member -name "IP" -membertype Noteproperty -value ""
$tab += $obj
Now i would like to count each combibation of SwitchName / Interface.
Exemple my arrays can contains the following amongt other value :
Switchname=foo,portX
Switchname=foo,portY
Switchname=foo,portX
Switchname=foo,portZ
Switchname=bar,portX
Switchname=bar,portZ
Switchname=bar,portT
I want to be able to get :
Switchname=foo,portX,2
Switchname=foo,portY,1
Switchname=foo,portZ,1
Switchname=bar,portX,1
Switchname=bar,portZ,1
Switchname=bar,portT,1
I'm currently thinking about using another table to count all of this. Any easier way to do that?
Thanks.

Use the Group-Object cmdlet:
PS C:\> $tab |Group-Object -Property SwitchName,Interface -NoElement
Count Name
----- ----
2 foo, portX
1 foo, portY
1 foo, portZ
1 bar, portX
1 bar, portZ
1 bar, portT

try Something like this:
$tab | select SwitchName, Interface , #{N="Number";E={$switchname=$_.SwitchName;$interface=$_.Interface; ($tab | where {$_.SwitchName -eq $switchname -and $_.Interface -eq $interface }).Count}}

Related

Powershell 2.0 random $null addition from Add-Member

My goal is to save some info into a variable that later will be written out ($Server).
I have created a cmdlet that gets some info from the CPU, which gives me the result i want to add into my server variable.
When i add it i get a $null value.
PS C:\> $CPU = Get-CPUInfo -Computername .
PS C:\> $CPU
CPUSpecification CPUCurrentClockSpeed CPUMaxClockSpeed Socket
---------------- -------------------- ---------------- ------
Intel(R) Core(TM) i5-6200U CPU # 2.30GHz 2300 2400 {#{SocketDesignation=U3E1; NumberOfCores=2; NumberOfLogicalProcessors=4}}
PS C:\> $Server = New-Object PSObject
PS C:\> Add-Member -InputObject $Server -MemberType NoteProperty -Name "CPU" -Value $CPU
PS C:\> $Server
CPU
---
{$null, #{CPUSpecification=Intel(R) Core(TM) i5-6200U CPU # 2.30GHz; CPUCurrentClockSpeed=2300; CPUMaxClockSpeed=2400; Socket=System.Object[]}}
PS C:\>
I would like to know why i get this $null inside, and how do i change it if it is some usefull information?
Later on i will create a .json file that stores my $Server variable, and it also saves the null value inside there.
I really do not like the idea of my users recieving null values where none are expected.
EDIT:
I have made this custom Get-CPUInfo cmdlet that i use, however it gives me what i need and no $null value:
function Get-CPUInfo
{
[CmdletBinding()]
Param
(
# Name of the computer to get version from
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[Alias("CN", "Host", "HostName")]
[string]$Computername
)
$MySocket = Get-WmiObject -Class Win32_Processor -ComputerName $ComputerName
$IsSocketArray = $MySocket -is [system.array]
$SocketInfo
$SocketInfoArray = #()
if(-not $IsSocketarray)
{
$SocketInfo = New-Object PSObject
Add-Member -InputObject $SocketInfo -MemberType NoteProperty -Name "SocketDesignation" -Value $MySocket.SocketDesignation
Add-Member -InputObject $SocketInfo -MemberType NoteProperty -Name "NumberOfCores" -Value $MySocket.NumberOfCores
Add-Member -InputObject $SocketInfo -MemberType NoteProperty -Name "NumberOfLogicalProcessors" -Value $MySocket.NumberOfLogicalProcessors
$SocketInfoArray += $SocketInfo
}
else
{
foreach ($s in $MySocket)
{
$SocketInfo = New-Object PSObject
Add-Member -InputObject $SocketInfo -MemberType NoteProperty -Name "SocketDesignation" -Value $s.SocketDesignation
Add-Member -InputObject $SocketInfo -MemberType NoteProperty -Name "NumberOfCores" -Value $s.NumberOfCores
Add-Member -InputObject $SocketInfo -MemberType NoteProperty -Name "NumberOfLogicalProcessors" -Value $s.NumberOfLogicalProcessors
$SocketInfoArray += $SocketInfo
}
}
$CPUSpecification = if($IsSocketarray){ $MySocket[0].Name} else{ $MySocket.Name}
$CPUCurrentClockSpeed = if($IsSocketarray){ $MySocket[0].CurrentClockSpeed} else{ $MySocket.CurrentClockSpeed}
$CPUMaxClockSpeed = if($IsSocketarray){ $MySocket[0].MaxClockSpeed} else{ $MySocket.MaxClockSpeed}
$CPUInfo = New-Object PSObject
Add-Member -InputObject $CPUInfo -MemberType NoteProperty -Name "CPUSpecification" -Value $CPUSpecification
Add-Member -InputObject $CPUInfo -MemberType NoteProperty -Name "CPUCurrentClockSpeed" -Value $CPUCurrentClockSpeed
Add-Member -InputObject $CPUInfo -MemberType NoteProperty -Name "CPUMaxClockSpeed" -Value $CPUMaxClockSpeed
Add-Member -InputObject $CPUInfo -MemberType NoteProperty -Name "Socket" -Value $SocketInfoArray
return $CPUInfo
}
PowerShell doesn't print null elements of an array when you display it directly, but it'll be printed in a compact representation of properties.
Let's check:
(Get-CPUInfo -Computername .).GetType()
Object[] System.Array
(Get-CPUInfo -Computername .).Count
2
(Get-CPUInfo -Computername .)[0] -eq $null
True
Something outputs a null value in the Get-CPUInfo function:
$SocketInfo
Remove it.

Powershell add-member calculated value

I'm writing a script that takes unstructured input, reformats it and spits out a CSV.
In one of the members, I want to do an NSLOOKUP of another member to get the DNS entry associated with the IP. However, a number of the entries have an IP of 0.0.0.0 e.g. it's a listening port, there's no client yet connected.
These throw up errors from NSLOOKUP, quite rightly, because there's no DNS entry for it.
So, I amended my code to only do the NSLOOKUP if the IP was not 0.0.0.0, otherwise return an empty string.
But I can't make it work.
The following throws up no errors:
$srcdata -split "`r`n"|foreach {
$obj = New-Object System.Object
$obj|Add-Member -MemberType NoteProperty -Name Connection_ID -Value $_.Split(",")[0]
$obj|Add-Member -MemberType NoteProperty -Name Filename -Value $_.Split(",")[1]
$obj|Add-Member -MemberType NoteProperty -Name MCP_Port -Value $_.Split(",")[2]
$obj|Add-Member -MemberType NoteProperty -Name Client_Port -Value $_.Split(",")[3]
$obj|Add-Member -MemberType NoteProperty -Name Port_State -Value $_.Split(",")[4]
$obj|Add-Member -MemberType NoteProperty -Name Client_IP -Value $_.Split(",")[5]
$obj|Add-Member -MemberType NoteProperty -Name Client_DNS -value {If ($obj.Client_IP -ne "0.0.0.0") {(NSLOOKUP $obj.Client_IP|Select-String Name).Line.ToString().Replace(" ","").Split(":")[1]} else {""}}
$obj|Add-Member -MemberType NoteProperty -Name Protocol_Stack -Value $_.Split(",")[6]
$outfile += $obj
}
But then if I inspect one of the objects in the array I see:
Connection_ID : 1
Filename : CCF_MARC1
MCP_Port : 2001
Client_Port : 0
Port_State : LISTEN
Client_IP : 0.0.0.0
Client_DNS : If ($obj.Client_IP -ne "0.0.0.0") {(NSLOOKUP $obj.Client_IP|Select-String Name).Line.ToString().Replace(" ","").Split(":")[1]} else {""}
Protocol_Stack : LEGACY
If I wrap in parentheses instead of in a scriptblock, so the line setting up the Client_DNS is as follows:
$obj|Add-Member -MemberType NoteProperty -Name Client_DNS -value (If ($obj.Client_IP -ne "0.0.0.0") {(NSLOOKUP $obj.Client_IP|Select-String Name).Line.ToString().Replace(" ","").Split(":")[1]} else {""})
I get:
If : The term 'If' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At K:\CodeSnippets\PowerShell\NW_CONN_TO_CSV.ps1:21 char:91
+ ... NS -value (If ($obj.Client_IP -ne "0.0.0.0") {(NSLOOKUP $obj.Client_IP|Selec ...
+ ~~
+ CategoryInfo : ObjectNotFound: (If:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
I'm sure I could get it to work as two separate lines of code, so do the If statement and put the result in a variable, then use that variable as the value in the add-member command, but I'm sure what I'm trying to do is eminently possible, I'm just missing something!
Any ideas?
You're interested in a ScriptProperty rather than a NoteProperty:
$obj |Add-Member -MemberType ScriptProperty -Name Client_DNS -Value {
nslookup $this.Client_IP |Select-String Name
}
You could use a regex to extract the name, something like this:
$outfile = $srcdata -split "[\r\n]" | % {
$v = $_.Split(",")
$re = [regex]::match((NSLOOKUP $v[5]), '(?<=Name:\s+)[^\s]+')
New-Object psobject -Property #{
Client_DNS = #('', $re.value)[$re.success]
Connection_ID = $v[0]
Filename = $v[1]
MCP_Port = $v[2]
Client_Port = $v[3]
Port_State = $v[4]
Client_IP = $v[5]
Protocol_Stack = $v[6]
}
}

Is it possible to get measure-object to return 0 rather than null/nothing for Sum when the array is empty?

I'm using measure-object to produce the count of the number of items in an array for a single property, and also the sum of the values of that property.
The array comes out of an imported CSV that is passed through where-object to filter and so it is possible that sometimes the array will be empty.
In the code where I'm building an array of objects with properties for creation of an output CSV, I access the .count and .sum properties of the measure-object cmdlet output for several different input arrays.
If the array measured was empty, the count will still have a value of 0 which I can use (I guess because even an empty array has a count (of 0), but the sum property doesn't exist/has no value. Therefore, the Add-Member cmdlet to add a property fails with "attempted to divide by zero".
The lines that fail are working out a percentage to put into the property value (using sums from two arrays) but the divisor is never zero, it's only the dividend that can sometimes be zero so I don't understand why I get the divide by zero error.
Anyone able to explain either how to force measure-object to return a sum of zero if there were no items in the array measured, or avoid the divide by zero error?
Sample code below:
$report = #()
$obj = New-Object System.Object
$obj | Add-Member -MemberType NoteProperty -Name Date -Value $Table[0].ENDDATE
$obj | Add-Member -MemberType NoteProperty -Name Environment -Value "PRODUCTION"
$obj | Add-Member -MemberType NoteProperty -Name Total_CPU_Seconds -Value ($ProdAllStats | Measure-Object -Property CPUTIME -Sum).Sum
$obj | Add-Member -MemberType NoteProperty -Name CompanyA_CPU_Seconds -Value ($CompAProdStats | Measure-Object -Property CPUTIME -Sum).Sum
$obj | Add-Member -MemberType NoteProperty -Name CompanyB_CPU_Seconds -Value ($CompBProdStats | Measure-Object -Property CPUTIME -Sum).Sum
$obj | Add-Member -MemberType NoteProperty -Name "%CompanyA_CPU" -Value ("{0:N2}" -f (($CompAProdStats | Measure-Object -Property CPUTIME -Sum).Sum/($ProdAllStats | Measure-Object -Property CPUTIME -Sum).Sum*100))
$obj | Add-Member -MemberType NoteProperty -Name "%CompanyB_CPU" -Value ("{0:N2}" -f (($CompBProdStats | Measure-Object -Property CPUTIME -Sum).Sum/($ProdAllStats | Measure-Object -Property CPUTIME -Sum).Sum*100))
$report += $obj
$obj = New-Object System.Object
$obj | Add-Member -MemberType NoteProperty -Name Date -Value $Table[0].ENDDATE
$obj | Add-Member -MemberType NoteProperty -Name Environment -Value "DEVELOPMENT"
$obj | Add-Member -MemberType NoteProperty -Name Total_CPU_Seconds -Value ($DevAllStats | Measure-Object -Property CPUTIME -Sum).Sum
$obj | Add-Member -MemberType NoteProperty -Name CompanyA_CPU_Seconds -Value ($CompADevStats | Measure-Object -Property CPUTIME -Sum).Sum
$obj | Add-Member -MemberType NoteProperty -Name CompanyB_CPU_Seconds -Value ($CompBDevStats | Measure-Object -Property CPUTIME -Sum).Sum
$obj | Add-Member -MemberType NoteProperty -Name "%CompanyA_CPU" -Value ("{0:N2}" -f (($CompADevStats | Measure-Object -Property CPUTIME -Sum).Sum/($DevAllStats | Measure-Object -Property CPUTIME -Sum).Sum*100))
$obj | Add-Member -MemberType NoteProperty -Name "%CompanyB_CPU" -Value ("{0:N2}" -f (($CompBDevStats | Measure-Object -Property CPUTIME -Sum).Sum/($DevAllStats | Measure-Object -Property CPUTIME -Sum).Sum*100))
$report += $obj
The divide by zero errors happen on the line of code working out the percentage for the DEVELOPMENT environment (which can be empty for CompanyB).
You could use an explicit type cast to make Measure-Object return a sum of zero instead of null, if the array happens to be empty:
(#() | Measure-Object -Property Foo -Sum).Sum -as [double]
From what I can see, Measure-Object returns null whenever you use the Property parameter with an input collection that has no items. The Count property is special, in that it always exists and will give you 0 when called on null. If the object has its own Count property that will be displayed.
One option is to not use the Property parameter like so:
($ProdAllStats.CpuTime | Measure-Object -Sum).Sum
I still find it kind of verbose so I'd probably create a function:
function Get-Sum {
param(
[string]$Property
)
if ($property -ne $null) {
($input.$property | Measure-Object -Sum).Sum
} else {
($input | Measure-Object -Sum).Sum
}
}

Creating and populating a hash table

I am looking to create either a non-jagged array or a hash table (I am not sure the difference nor what I need to get the job done). Here is what I am trying to do.
I would like to query a list of servers for several values and then store those values for output to a CSV file. Here is the code.
$allServers = "svr1","svr2","svr3"
$a = #{}
$outData = New-Object PSObject
$allServers | ForEach-Object {
$cpu = (Get-WmiObject win32_processor -ComputerName $_).length
$mem = (Get-WmiObject win32_physicalmemory -ComputerName $_).Capacity /1GB
$outData | Add-Member -Type NoteProperty -Name "SERVERNAME" -Value $_
$outData | Add-Member -Type NoteProperty -Name "#CPU" -Value $cpu
$outData | Add-Member -Type NoteProperty -Name "#GBRAM" -Value $mem
}
Write-Host $outData
I am getting errors because it seems like it is trying to create the same entries repeatedly. Is it possible to make an empty hash table (or non-jagged array) with column names and then just populate values?
Create the object inside the loop, output it, and assign the value of the whole pipeline to your array variable:
$allServers = "svr1","svr2","svr3"
$a = $allServers | ForEach-Object {
$cpu = (Get-WmiObject win32_processor -ComputerName $_).length
$mem = (Get-WmiObject win32_physicalmemory -ComputerName $_).Capacity /1GB
$outData = New-Object PSObject
$outData | Add-Member -Type NoteProperty -Name "SERVERNAME" -Value $_
$outData | Add-Member -Type NoteProperty -Name "#CPU" -Value $cpu
$outData | Add-Member -Type NoteProperty -Name "#GBRAM" -Value $mem
$outData
}
$a | Export-Csv $path -NoTypeInformation

Add Member to get NIC Info Gives Error for Servers with More than One Nic ( powershell.)

Im trying to genreate a report for NIc Card info using powershell, & use add member to append the properties, but if a server is having more than 1 NIC, add members return an error "Do you want to owerwrite property" Use -force, could any one please help me to sort out the issue, also im having an array $output=#() into which im appending all these inputs,i Tried adding a for loop to get the no of NICS & iterate thru them one by one as an array, i see no output, can some one help me.
<#NIC card info Check#>
$colItems1 = get-wmiobject -class "Win32_NetworkAdapter" -namespace "root\CIMV2" -computername $compname
$colItems = get-wmiobject -class "Win32_NetworkAdapterconfiguration" -namespace "root\CIMV2" -computername $compname
$lengthcol=($colItems1).length
for ($i=0;$i-lt$length;$i++){
foreach ($objitem in $colItems)
{
# Match the current $objItem with the correct $ColItems1 element.
$objItem1 = $colItems1| where-object{$_.Caption -eq $objItem.Caption}
# A test is needed here as the loop will find a number of virtual network configurations with no "Hostname"
# So if the "Hostname" does not exist, do NOT display it!
if ($objItem.ipenabled -eq "true" -and $objitem1.netconnectionid) {
# Write to screen
#write-host "Caption: " $objItem.Caption
$nicname[$i]=$objitem1.netconnectionid
$dhcpenabled[$i]=$objItem.DHCPEnabled
$ipaddress[$i]=$objItem.IPAddress
$ipsubnet[$i]=$objItem.IPSubnet
$gateway[$i]=$objItem.DefaultIPGateway
$dhcpserver[$i]=$objItem.DHCPServer
$DNSDomain[$i]=$objItem.DNSDomain
$DNSDomainSearchOrder[$i]=$objItem.DNSDomainSuffixSearchOrder
$DNSServerSearchOrder[$i]=$objItem.DNSServerSearchOrder
$output | Add-Member -MemberType Noteproperty -Name NICCardName[$i] -Value $nicname[$i]
$output | Add-Member -MemberType Noteproperty -Name DHCPEnabled[$i] -Value $dhcpenabled[$i]
$output | Add-Member -MemberType Noteproperty -Name IPAddress[$i] -Value $ipaddress[$i]
$output | Add-Member -MemberType Noteproperty -Name SubnetMask[$i] -Value $ipsubnet[$i]
$output | Add-Member -MemberType Noteproperty -Name Gateway[$i] -Value $gateway[$i]
$output | Add-Member -MemberType Noteproperty -Name DHCPServer[$i] -Value $dhcpserver[$i]
$output | Add-Member -MemberType Noteproperty -Name DNSDomain[$i] -Value $DNSDomain[$i]
$output | Add-Member -MemberType Noteproperty -Name DNSDomainSuffixSearchOrder[$i] -Value $DNSDomainSearchOrder[$i]
$output | Add-Member -MemberType Noteproperty -Name DNSServerSearchOrder[$i] -Value $DNSServerSearchOrder[$i]
}
}
}
$outputs+=$output
Try this:
Get-WmiObject Win32_NetworkAdapter -ComputerName $computer| ForEach-Object {
$NetConnectionId = $_.NetConnectionId
$nac = $_.GetRelated('Win32_NetworkAdapterconfiguration') | Select-Object IPEnabled,DHCPEnabled,IPAddress,IPSubnet,DefaultIPGateway,DHCPServer,DNSDomain,DNSDomainSuffixSearchOrder,DNSServerSearchOrder
$nac | Select-Object *,#{Name='NetConnectionId';Expression={$NetConnectionId}}
}
UPDATE (per poster request):
$compname='.'
$colItems1 = get-wmiobject -class Win32_NetworkAdapter -computername $compname
$colItems = get-wmiobject -class Win32_NetworkAdapterconfiguration -computername $compname
foreach ($objitem in $colItems)
{
$objItem1 = $colItems1 | where-object{$_.Caption -eq $objItem.Caption}
if ($objItem.ipenabled -eq $true -and $objitem1.netconnectionid)
{
$output = new-object -typename psobject
$output | Add-Member -MemberType Noteproperty -Name NICCardName -Value $objitem1.netconnectionid
$output | Add-Member -MemberType Noteproperty -Name DHCPEnabled -Value $objItem.DHCPEnabled
$output | Add-Member -MemberType Noteproperty -Name IPAddress -Value $objItem.IPAddress
$output | Add-Member -MemberType Noteproperty -Name SubnetMask -Value $objItem.IPSubnet
$output | Add-Member -MemberType Noteproperty -Name Gateway -Value $objItem.DefaultIPGateway
$output | Add-Member -MemberType Noteproperty -Name DHCPServer -Value $objItem.DHCPServer
$output | Add-Member -MemberType Noteproperty -Name DNSDomain -Value $objItem.DNSDomain
$output | Add-Member -MemberType Noteproperty -Name DNSDomainSuffixSearchOrder -Value $objItem.DNSDomainSuffixSearchOrder
$output | Add-Member -MemberType Noteproperty -Name DNSServerSearchOrder -Value $objItem.DNSServerSearchOrder -PassThru
}
}

Resources