Powershell 2.0 random $null addition from Add-Member - arrays

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.

Related

Looping and adding extra properties to a Object

I'm running a simple script to check if several specific services are running on an array of computers. It works fine, except the each 'row' appears' for every iteration of the loop. In this case 3 times. How do I edit/add to a property of an existing object? I.e. I want to add extra properties for the same object/row...
ComputerName Qualys Cloud Agent SplunkForwarder Service Cb Defense
------------ ------------------ ----------------------- ----------
dc01 Found Found Found
dc01 Found Found Found
dc01 Found Found Found
dc02 Found Found Found
dc02 Found Found Found
dc02 Found Found Found
ds01 Found Found Found
ds01 Found Found Found
ds01 Found Found Found
$ComputerName = 'dc01','ds01','dc02'
$ServiceList ='Qualys Cloud Agent',
'SplunkForwarder Service',
'Cb Defense'
$objarray = #()
$obj = #()
$ServiceArray = get-service -ComputerName $ComputerName -DisplayName $ServiceList | select-object -property MachineName,DisplayName,Name,Status
Foreach ($Computer in $ComputerName){
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "ComputerName" -Value $Computer
Foreach($Service in $ServiceList){
If ((gsv -computername $computer -displayname $Service).Status -eq 'Running'){
#write-output "Found $Service on $Computer"
$obj | Add-Member -MemberType NoteProperty -Name $service -Value 'Found'
$objArray += $obj
}
else{
#write-output "Not Found"
$obj | Add-Member -MemberType NoteProperty -Name $service -Value 'Not Found'
$objArray += $obj
}
}
}
$objarray | sort computername
Move the $objArray += $obj statement outside the inner loop - this way each object is only referenced by the array once:
Foreach ($Computer in $ComputerName){
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "ComputerName" -Value $Computer
Foreach($Service in $ServiceList){
If ((gsv -computername $computer -displayname $Service).Status -eq 'Running'){
#write-output "Found $Service on $Computer"
$obj | Add-Member -MemberType NoteProperty -Name $service -Value 'Found'
}
else{
#write-output "Not Found"
$obj | Add-Member -MemberType NoteProperty -Name $service -Value 'Not Found'
}
}
# Only need to add the resulting object ONCE
$objArray += $obj
}
I personally prefer constructing each list of object properties as a dictionary, and then convert + output it at the very end of the loop - at which point we simply assign the result of the entire foreach() statement to the desired variable:
$objArray = foreach($Computer in $ComputerName){
# Create dictionary to keep track of the new properties
$props = [ordered]#{ ComputerName = $Computer}
foreach($Service in $ServiceList){
# Populate dictionary with remaining properties inside the inner loop
if((gsv -computername $computer -displayname $Service).Status -eq 'Running'){
$props["$service"] = 'Found'
}
else{
$props["$service"] = 'Not Found'
}
}
# convert to object,
[pscustomobject]$props
}
If you want to add a property to an object, pipe the object to "add-member". Here is a quick example:
$files = Get-childitem "$env:USERPROFILE\Documents\*"
Foreach ($item in $files)
{
$item | Add-Member -MemberType NoteProperty -Name "extention" -Value $item.Name.Substring($item.name.Length - 3)
}
$files.extention

"Counting" in an arrays using powershell

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}}

Create Powershell Object From Loop Containing Multiple Users

I need to create a Powershell object, array or hash table to store a list of users and assorted details, these are extracted from a CSV file and located using Get-ADUser. As below:
$userList = Import-CSV $CSVInputFile
$users = #{}
Foreach ($csvUser in $userList)
{
$userSearchString = $csvUser | Select -ExpandProperty SamAccountName
$currentUser = (Get-ADUser -Filter {SamAccountName -eq $userSearchString} `
-Properties PasswordExpired,PasswordLastSet,EmailAddress |
Where {$_.Enabled -eq "True"})
If ($currentUser.EmailAddress -ne $null)
{
$currentUserEmailString = $csvUser | Select -ExpandProperty EmailAddress
$currentUserEmailString = ($currentUserEmailString -as [string])
$currentUser.EmailAddress = $currentUserEmailString
}
$Users = New-Object PSObject -Property #{
DistinguishedName = $currentUser.DistinguishedName
EmailAddress = $currentUser.EmailAddress
Enabled = $currentUser.Enabled
GivenName = $currentUser.GivenName
Name = $currentUser.Name
PasswordExpired = $currentUser.PasswordExpired
PasswordLastSet = $currentUser.PasswordLastSet
SamAccountName = $currentUser.SamAccountName
Surname = $currentUser.Surname
}
$Users
}
How can I add the details of each user for each iteration of the loop to the object.
I want to end up with an object containing the details of a number of users, same as the output directly from Get-ADUser:
Name SamAccountName EmailAddress
---- -------------- ------------
User1 user1 user1#domain.com
User2 user2 user2#domain.com
User3 user3 user3#domain.com
Any help would be greatly appreciated!
Not sure if I'm missing the point on this but I see you are building a custom object right in your loop. The only issue I do see is you are not keeping the results after each loop. Rather you are destroying the objects history.
I would change the declaration of $users to an array $users = #() and instead of populating a user hashtable into users add the current object into the array. You will then have an array of hashtables:
$Users += New-Object PSObject -Property #{...
Then you could the $Users output line outside the loop and you will have the whole thing. Then you could just output to a Select to get the output you desire.
$Users | Select-Object name,SamAccountName,EmailAddress
There is a potential major drawback of this approach though. When using += on arrays a new array is created and resized for the new element and the old array is discarded. This has huge performance implications for larger arrays.
An even better way to approach this would be to leverage the pipeline. This would be a performance boost when you have larger user groups.
Import-CSV $CSVInputFile | ForEach-Object{
$userSearchString = $_.SamAccountName
$currentUser = Get-ADUser -Filter {SamAccountName -eq $userSearchString} `
-Properties PasswordExpired,PasswordLastSet,EmailAddress |
Where {$_.Enabled -eq "True"}
If ($currentUser.EmailAddress -ne $null){
$currentUser.EmailAddress = $_.EmailAddress
}
[pscustomobject][ordered]#{
DistinguishedName = $currentUser.DistinguishedName
# ..... truncated
Surname = $currentUser.Surname
}
}
Now you could send that to something like Export-CSV or just save it into a variable. Your options are open now. [pscustomobject][ordered] are type accelerators available in PowerShell v3.0+
Define an $users as Array
$users = #()
and append the New-Object into $Users.
$Users += New-Object
Can't believe both of you guys got in before me! Oh well.
Hope this helps anyway.
$userList = Import-CSV $CSVInputFile
$users = #()
Foreach ($csvUser in $userList)
{
$userSearchString = $csvUser | Select -ExpandProperty SamAccountName
$currentUser = (Get-ADUser -Filter {SamAccountName -eq $userSearchString} `
-Properties PasswordExpired,PasswordLastSet,EmailAddress |
Where {$_.Enabled -eq "True"})
If ($currentUser.EmailAddress -ne $null)
{
$currentUserEmailString = $csvUser | Select -ExpandProperty EmailAddress
$currentUserEmailString = ($currentUserEmailString -as [string])
$currentUser.EmailAddress = $currentUserEmailString
}
#clears the properties of the previous object and starts collecting properties
$UserObj = New-Object PSObject
Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "DistinguishedName" -Value $($currentUser.DistinguishedName)
Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "EmailAddress" -Value $($currentUser.EmailAddress)
Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "Enabled" -Value $($currentUser.Enabled)
Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "GivenName" -Value $($currentUser.GivenName)
Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "UserName" -Value $($currentUser.Name)
Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "PasswordExpired" -Value $($currentUser.PasswordExpired)
Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "PasswordLastSet" -Value $($currentUser.PasswordLastSet)
Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "SamAccountName" -Value $($currentUser.SamAccountName)
Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "Surname" -Value $($currentUser.Surname)
#saves the properties in an array that exists outside of the loop to preserve information beyond one interation
$users += $UserObj
}
$users | Format-Table -Property UserName,SamAccountName,EmailAddress

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