I am trying to update an hash table entry (Content, which is an array) where I find values - but when I try to set the value for $_ it applies to all entries in the entire hash ($hash).
$ContentArray = #($null, $null)
$Comparison | Add-Member -MemberType NoteProperty -Name "Content" -value $ContentArray
If($GetAdvancedData -eq "true"){
$Hash| ForEach-Object{
If ($_.VarianceType -ne "Missing")
{
$_.Item
$id = $_.id[0]
$elem = $_.elementName
Write-debug "Checking $elem"
Write-debug "Checking for version $id"
try{
$content = Get-VersionContent -FilteredVersionID $id
Write-debug "Content found"
Write-debug "$content"
# Various tests to try and set the value:
#ForEach ($Key in $Hash.GetEnumerator() | Where-Object {$_.id -eq $id}){$Key.Content[0] = $content}
#$Hash.Content[0] = "$content" | Where-Object {$Hash.id[0] -eq $id}
#$Hash.DiffType = "Content"| Where-Object {$_.id[0] -eq $id}
# $_.content.SetValue("$content","0")
$_.Content[0] = $content
# Reset $content to Null
$content = $null
}
catch
{
Write-debug "No content found"
}
}
}
I have tried setting it via a where clause based on another key value, using SetValue, and simply doing an = statement, but in each case it sets the entire hash tables content to $content - I feel as if I must be missing something obvious, but I can't see why (if I use the PowerShell ISE and debug $_ returns only the single record from the ForEach loop)
A silly mistake-
$Hash.GetEnumerator() | Where-Object {$_.id[0] -eq $id} | foreach{$_.Content = $content,$null}
did the trick for me!
Related
I run an all users command for calendar delegation. I then report. The issue is how do I include someone that has no calendar delegation ? (Code Below)
In this line If ($null -ne $DelegateCal) I make sure someone has calendar delegation then build the object.
If I don't use += I am not sure how to build the object when I add a Else for the $null
<#All Google Calendar delegate report#>
# filename function
Import-Module C:\tasks\Modules\MRNAP\MRNAP.psm1
$AllGoogleUsers = gam print users fields suspended | ConvertFrom-Csv | Where-Object { $_.suspended -eq $False } | Select-Object -ExpandProperty PrimaryEmail
ForEach ($UserEmail in $AllGoogleUsers) {
$DelegateCal = gam calendar $UserEmail print acls | convertfrom-csv | Where-Object { $_.'scope.type' -eq 'user' -and $_.'Scope.value' -ne $UserEmail } -ErrorAction SilentlyContinue
If ($null -ne $DelegateCal) {
$CalendarDelegateList = foreach ($line in $DelegateCal) {
[PSCustomObject]#{
Owner = $line.calendarId
Type = 'Calendar'
Delegate = $line.'scope.value'
Role = $line.role
}
}
}
}
$CalendarDelegateList = $CalendarDelegateList | Sort-Object -Property Owner
$filename = MRNAP -ReportName WhoIsCalendarDelegated -Move
$CalendarDelegateLis | Export-Csv $filename -NoTypeInformation | Format-Table text-align=left -AutoSize
This is how I would do it with +=
$AllGoogleUsers = gam print users fields suspended | ConvertFrom-Csv | Where-Object { $_.suspended -eq $False } | Select-Object -ExpandProperty PrimaryEmail
ForEach ($UserEmail in $AllGoogleUsers) {
$DelegateCal = gam calendar $UserEmail print acls | convertfrom-csv | Where-Object { $_.'scope.type' -eq 'user' -and $_.'Scope.value' -ne $UserEmail } -ErrorAction SilentlyContinue
If ($null -ne $DelegateCal) {
foreach ($line in $DelegateCal) {
$CalendarDelegateList += [PSCustomObject]#{
Owner = $UserEmail
Type = 'Calendar'
Delegate = $line.'scope.value'
Role = $line.role
}
}
}
Else {
$CalendarDelegateList += [PSCustomObject]#{
Owner = $UserEmail
Type = 'Calendar'
Delegate = 'None'
Role = 'None'
}
}
}
It is always preferable to let PowerShell collect statement output in an array for you rather than building a list of outputs manually - both for concision and performance; see this answer for more information.
This even works with nested foreach loops, as in your case.
Applied to your scenario (abridged):
[array] $CalendarDelegateList =
foreach ($UserEmail in $AllGoogleUsers) {
$DelegateCal = gam calendar $UserEmail print acls | ConvertFrom-Csv | Where-Object { $_.'scope.type' -eq 'user' -and $_.'Scope.value' -ne $UserEmail } -ErrorAction SilentlyContinue
If ($null -ne $DelegateCal) {
foreach ($line in $DelegateCal) {
# Construct *and ouput* a [pscustomobject] instance.
[PSCustomObject]#{
Owner = $UserEmail
# ...
}
}
}
Else {
[PSCustomObject]#{
Owner = $UserEmail
# ...
}
}
}
All [pscustomobject] instances (implicitly) output from inside the foreach loop (whether directly or from the nested one) are automatically collected in variable $CalendarDelegateList.
Note:
With two or more output objects from the loop, the $CalendarDelegateList variable receives a regular PowerShell array (of type [object[]]).
The [array] type constraint (short for: [object[]]) additionally ensures that the result is an array even if the loop outputs only one object.
Iam trying to write a script to notify if a VMware VM Custom attribute has a value or if the value is null.
I need the VM name and the Output Value (either Null or Not Null). Here is what I have but doesn't return the accurate information
$vms = Get-VM
foreach ($vm in $vms) {
$tag = $vm | Get-Annotation -CustomAttribute "Backup"
if ($tag.value -eq '$null'){
Write-Output "$vm Attribute doesnt have a value"
}
else {
Write-Output "$vm Attribute has a value assigned"
}
}
Unless you're specifically looking for the literal string value '$null', you probably want to change the comparison to $null -eq $tag.value
You could create a new object with 2 properties:
$vms = Get-VM
foreach ($vm in $vms) {
$tag = $vm | Get-Annotation -CustomAttribute "Backup"
if ($null -eq $tag.value){
$result = "$vm Attribute doesnt have a value"
}
else {
$result = Write-Output "$vm Attribute has a value assigned"
}
# output object with Name + result
[pscustomobject]#{
Name = $vm.Name
Result = $result
}
}
Another, perhaps more PowerShell-idiomatic approach would be to create a similar object with the Select-Object cmdlet:
Get-VM |Select-Object Name,#{Name='HasBackupAttribute';Expression={ $null -eq ($_ | Get-Annotation -CustomAttribute "Backup").Value }}
When looking at dealing with $null comparisons, see this SO Q&A:
In PowerShell, why is $null -lt 0 = $true? Is that reliable?
I do not have VMware at the moment, but in my small Hyper-V lab, running the following delivers the shown results:
Try
{
(
Get-VM |
Where-Object -Property FloppyDrive -eq $null |
Select Name, FloppyDrive -ErrorAction SilentlyContinue
).Count
}
Catch { Write-Warning -Message 'No no records returned'}
# Results
<#
4
#>
Try
{
(
Get-VM |
Where-Object -Property FloppyDrive -ne $null |
Select Name, FloppyDrive -ErrorAction SilentlyContinue
).Count
}
Catch { Write-Warning -Message 'No no records returned'}
# Results
<#
WARNING: No no records returned
#>
The results are the same using these as well.
Try
{
(
Get-VM |
Where-Object -Property FloppyDrive -Match $null |
Select Name, FloppyDrive -ErrorAction SilentlyContinue
).Count
}
Catch { Write-Warning -Message 'No no records returned'}
Try
{
(
Get-VM |
Where-Object -Property FloppyDrive -NotMatch $null |
Select Name, FloppyDrive -ErrorAction SilentlyContinue
).Count
}
Catch { Write-Warning -Message 'No no records returned'}
In your use case, try this refactor:
(Get-VM).Name |
foreach {
if ((Get-VM -Entity $PSitem | Get-Annotation -CustomAttribute 'Backup') -eq $null)
{ "$PSItem - Attribute doesnt have a value" }
else {"$PSItem - Attribute has a value assigned"}
}
Or...
(Get-VM).Name |
foreach {
if ((Get-VM -Entity $PSitem | Get-Annotation -CustomAttribute 'Backup') -Match $null)
{ "$PSItem - Attribute doesnt have a value" }
else {"$PSItem - Attribute has a value assigned"}
}
Annotation values are strings. When there is no value present, the string is considered empty rather than null. So the $null -eq value test will not yield the desired results. You can simply perform an implicit boolean conversion of the value to determine if it is empty.
$vms = Get-VM
foreach ($vm in $vms) {
$tag = $vm | Get-Annotation -CustomAttribute "Backup"
# Empty string returns false. Nonempty string returns true.
if ($tag.value){
Write-Output "$vm Attribute has a value assigned"
}
else {
Write-Output "$vm Attribute doesn't have a value"
}
}
You will discover that $tag.value | Get-Member returns a type System.String. So when value seemingly has no value, it actually is an empty string. You can perform a variety of tests to determine if the value is empty. An empty string value inside of an if statement evaluates to False. See below for some examples, which can all be used inside of if statements.
$Empty = [pscustomobject]#{value = ''}
$NotEmpty = [pscustomobject]#{value = 'My String'}
# Test 1 Using IsNullOrEmpty static method
[string]::IsNullOrEmpty($Empty.value)
True
[string]::IsNullOrEmpty($NotEmpty.value)
False
# Test 2 Using [bool] type accelerator
[bool]$Empty.value
False
[bool]$NotEmpty.value
True
# Test 3 Using length property. Empty string has length of 0.
$Empty.value.length -eq 0
True
$NotEmpty.value.length -eq 0
False
# Test 4 Using if statement. ! in front of an expression negates its boolean value
if ($Empty.value) { "Value is not empty" } else { "Value is empty" }
Value is empty
if ($NotEmpty.value) { "Value is not empty" } else { "Value is empty" }
Value is not empty
if (!$Empty.value) { "Value is empty" }
Value is empty
I have this awesome script I use to generate a list of folders with their assigned security groups and each user in each group.
When I run it, I type .\getfolderacls.ps1 -verbose | export-csv c:\temp\filename.csv -notypeinformation.
That works perfectly, but I'd like to hardcode the | export-csv... part so that I can just run it without the arguments (or are they parameters?).
I tried simply appending | export-csv c:\temp\test.csv -notypeinformation to the bottom of the script, but that throws the error An empty pipe element is not allowed.
Script:
[CmdletBinding()]
Param (
[ValidateScript({Test-Path $_ -PathType Container})]
[Parameter(Mandatory=$false)]
[string]$Path
)
Write-Verbose "$(Get-Date): Script begins!"
Write-Verbose "Getting domain name..."
$Domain = (Get-ADDomain).NetBIOSName
Write-Verbose "Getting ACLs for folder $Path"
Write-Verbose "...and all sub-folders"
Write-Verbose "Gathering all folder names, this could take a long time on bigger folder trees..."
$Folders = Get-ChildItem -Path I:\foldername -Directory -Recurse -Depth 2
Write-Verbose "Gathering ACL's for $($Folders.Count) folders..."
ForEach ($Folder in $Folders)
{ Write-Verbose "Working on $($Folder.FullName)..."
$ACLs = Get-Acl $Folder.FullName | ForEach-Object { $_.Access | where{$_.IdentityReference -ne "BUILTIN\Administrators" -and $_.IdentityReference -ne "BUILTIN\Users" }}
ForEach ($ACL in $ACLs)
{ If ($ACL.IdentityReference -match "\\")
{ If ($ACL.IdentityReference.Value.Split("\")[0].ToUpper() -eq $Domain.ToUpper())
{ $Name = $ACL.IdentityReference.Value.Split("\")[1]
If ((Get-ADObject -Filter 'SamAccountName -eq $Name').ObjectClass -eq "group")
{ ForEach ($User in (Get-ADGroupMember $Name -Recursive | Select -ExpandProperty Name))
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = $Name
User = $User
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
Else
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = ""
User = Get-ADUser $Name | Select -ExpandProperty Name
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
Else
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = ""
User = $ACL.IdentityReference.Value
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
}
}
Write-Verbose "$(Get-Date): Script completed!"
Your script's output is being produced inside a foreach loop - ForEach ($Folder in $Folders) ... (as opposed to via the ForEach-Object cmdlet, which, unfortunately, is also aliased to foreach).
In order to send a foreach loop's output to the pipeline, you can wrap it in a script block ({ ... }) and invoke it with the dot-sourcing operator (.).
Alternatively, use the call operator (&), in which case the loop runs in a child scope.
Here are simplified examples:
# FAILS, because you can't use a foreach *loop* directly in a pipeline.
PS> foreach ($i in 1..2) { "[$i]" } | Write-Output
# ...
An empty pipe element is not allowed.
# ...
# OK - wrap the loop in a script block and invoke it with .
PS> . { foreach ($i in 1..2) { "[$i]" } } | Write-Output
[1]
[2]
Note: I'm using Write-Output as an example of a cmdlet you can pipe to, solely for the purpose of this demonstration. What's required in your case is to wrap your foreach loop in . { ... } and to follow it with | Export-Csv ... instead of Write-Output.
Using . { ... } or & { ... } sends the output generated inside the loop to the pipeline as it is being produced, one by one, aka in streaming fashion - as (typically) happens with output produced by a cmdlet.
An alternative is to use $(...), the subexpression operator (or #(...), the array-subexpression operator, which works the same in this scenario), in which case the loop output is collected in memory as a whole, up front, before it is sent through the pipeline - this is typically faster, but requires more memory:
# OK - call via $(...), with output collected up front.
PS> $(foreach ($i in 1..2) { "[$i]" }) | Write-Output
[1]
[2]
To spell the . { ... } solution out in the context of your code - the added lines are marked with # !!! comments (also note the potential to improve your code based on Lee_Dailey's comment on the question):
[CmdletBinding()]
Param (
[ValidateScript({Test-Path $_ -PathType Container})]
[Parameter(Mandatory=$false)]
[string]$Path
)
Write-Verbose "$(Get-Date): Script begins!"
Write-Verbose "Getting domain name..."
$Domain = (Get-ADDomain).NetBIOSName
Write-Verbose "Getting ACLs for folder $Path"
Write-Verbose "...and all sub-folders"
Write-Verbose "Gathering all folder names, this could take a long time on bigger folder trees..."
$Folders = Get-ChildItem -Path I:\foldername -Directory -Recurse -Depth 2
Write-Verbose "Gathering ACL's for $($Folders.Count) folders..."
. { # !!!
ForEach ($Folder in $Folders)
{ Write-Verbose "Working on $($Folder.FullName)..."
$ACLs = Get-Acl $Folder.FullName | ForEach-Object { $_.Access | where{$_.IdentityReference -ne "BUILTIN\Administrators" -and $_.IdentityReference -ne "BUILTIN\Users" }}
ForEach ($ACL in $ACLs)
{ If ($ACL.IdentityReference -match "\\")
{ If ($ACL.IdentityReference.Value.Split("\")[0].ToUpper() -eq $Domain.ToUpper())
{ $Name = $ACL.IdentityReference.Value.Split("\")[1]
If ((Get-ADObject -Filter 'SamAccountName -eq $Name').ObjectClass -eq "group")
{ ForEach ($User in (Get-ADGroupMember $Name -Recursive | Select -ExpandProperty Name))
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = $Name
User = $User
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
Else
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = ""
User = Get-ADUser $Name | Select -ExpandProperty Name
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
Else
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = ""
User = $ACL.IdentityReference.Value
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
}
}
} | Export-Csv c:\temp\test.csv -notypeinformation # !!!
Write-Verbose "$(Get-Date): Script completed!"
I want to make a script that will check whether or not a directory exists on each computer in "computers.csv".
This is what I've come up with:
$results = #()
$computers = Get-Content "C:\Users\me\Desktop\Notes\Computers.csv"
foreach ($computer in $computers) {
$path = Test-Path "\\$computer\c$\Program Files\Folder\"
if ($path -eq $true)
$Output = "True"
else
$Output = "False"
}
$details = #{
Computer_Name = $computer
Output = $Output
}
$results += New-Object PSObject -Property $details
$results |
Select-Object -Property Computer_Name,Output |
Export-Csv c:\results.csv -NoTypeInformation
Script is failing and I'm not entirely sure why. I need the script to export to a CSV due to how many computers are being queried.
You've got several syntax errors. You're missing brackets with if and else, and your foreach closing bracket is in the wrong place. Try this:
$results = #()
$computers = Get-Content "C:\Users\me\Desktop\Notes\Computers.csv"
foreach ($computer in $computers) {
$path = Test-Path "\\$computer\c$\Program Files\Folder\"
If ($path -eq $true) {
$Output = "True"
}
Else {
$Output = "False"
}
$details = #{
Computer_Name = $computer
Output = $Output
}
$results += New-Object PSObject -Property $details
}
$results | select-object -property Computer_Name, Output | Export-csv c:\results.csv -NoTypeInformation
That said, this pattern is one that should be avoided:
$results = #()
foreach ($item in $set) {
$results += $item
}
$results
The problem is that $results += $item copies the entire array into a new array and then adds the new item. It's a huge overhead as the size of the array increases.
Try something like this instead:
Get-Content "C:\Users\me\Desktop\Notes\Computers.csv" | ForEach-Object {
[PSCustomObject]#{
Computer_Name = $_
Output = Test-Path "\\$_\c$\Program Files\Folder\"
}
} | Export-Csv -Path C:\results.csv -NoTypeInformation
I have a CSV file that contains subnet information that I will use to populate a CSV file that has server information in it. I'm starting by importing the subnet information and when processing it, I'm trying to add multiple members to the initial hashtable, but it is not behaving as expected.
The following code processes the first item as expected, creating a new column with the correct information. The code indicates that it processes at least through two more sections, but the members are not added. How do I change the code to allow the creation of multiple members to a single array? The goal is to have each subnet's gateway field (column) be unique to that subnet.
The purpose of the five variables (variableA-E) is to mimic what is occuring in the real code. The real code runs comparisons from the hashtable, but that is not neccessary. I'm willing to change that portion if needed.
CSV file contents:
NetworkName,Subnet,VLANID,Gateway,VLAN
Servers,"192.168.1.0/24","2041","192.168.1.1","ServerVLAN-2041"
Workstations,"192.168.2.0/24","1001","192.168.2.1","WorkstationVLAN-1001"
DMZ,"172.16.0.0/28","340","172.16.0.1","DMZVLAN-340"
Servers,"192.168.3.0/24","2043","192.168.3.1","ServerVLAN-2043"
Workstations,"192.168.4.0/24","1004","192.168.4.1","WorkstationVLAN-1004"
DMZ,,,,
CODE:
$csvfile = "C:\temp\testfile.csv"
$hashArray = Import-CSV $csvfile
$variableA = "192.168.1.0"
$variableB = "192.168.2.0"
$variableC = "192.168.3.0"
$variableD = "172.16.0.1"
$variableE = "192.168.5.0"
$hashArray | % {
if ($_.subnet) { $variable = ($_.subnet).split("/")[0] }
Else { $variable = $null }
if ($variable -eq $variableA -and $variable -ne $null)
{
$_ | add-member "ServerGW1" -NotePropertyValue $_.gateway
Write-Host "Added Server gateway 1: "$_.gateway -ForegroundColor Yellow
}
if ($variable -eq $variableC -and $variable -ne $null)
{
$_ | add-member "ServerGW2" -NotePropertyValue $_.gateway
Write-Host "Added Server gateway 2: "$_.gateway -ForegroundColor Yellow
}
if ($variable -eq $variableB -and $variable -ne $null)
{
$_ | add-member "WorkstationGW1" -NotePropertyValue $_.gateway
Write-Host "Added Workstation gateway 1: "$_.gateway -ForegroundColor Yellow
}
if ($variable -eq $variableD -and $variable -ne $null)
{
$_ | add-member "DMZGW1" -NotePropertyValue $_.gateway
Write-Host "Added DMZ gateway 1: "$_.gateway -ForegroundColor Yellow
}
if ($variable -eq $variableE -and $variable -ne $null)
{
$_ | add-member "WorkstationGW2" -NotePropertyValue $_.gateway
Write-Host "Added Workstation gateway 2: "$_.gateway -ForegroundColor Yellow
}
}
$hashArray | Out-GridView
Out-GridView OUTPUT:
Console OUTPUT:
Expected output:
Out-GridView uses properties from the first object to render columns. All new columns (except ServerGW1) are missing because are not initialized in the first object in your $hashArray. You can initialize with $null value all properties for all rows or provide a list of properties to select before you output your result to Out-GridView
$hashArray | Select-Object NetworkName,Subnet,VLANID,Gateway,VLAN, ServerGW1, ServerGW2,WorkstationGW1,WorkstationGW2,DMZGW1 | Out-GridView
Init all properties:
$hashArray | % {
$variable =if ($_.subnet) { ($_.subnet).split("/")[0] }Else { $null }
$_ | add-member "ServerGW1" -NotePropertyValue $(if ($variable -eq $variableA){ $_.gateway}Else { $null })
$_ | add-member "ServerGW2" -NotePropertyValue $(if ($variable -eq $variableC){ $_.gateway}Else { $null })
$_ | add-member "WorkstationGW1" -NotePropertyValue $(if($variable -eq $variableB){ $_.gateway}Else { $null })
$_ | add-member "DMZGW1" -NotePropertyValue $(if ($variable -eq $variableD ){ $_.gateway}Else { $null })
$_ | add-member "WorkstationGW2" -NotePropertyValue $(if ($variable -eq $variableE){ $_.gateway}Else { $null })
}
$hashArray | Out-GridView
To complement cezarypiatek's helpful answer, which provides the crucial pointer:
All formatting cmdlets, including Out-GridView decide what properties (columns) to show based on the first input object, so to guarantee that the all columns of interest are shown, you must ensure that (at least) the first input object contains all properties of interest.
With that in mind, here's a streamlined version of your approach that does that:
$csvfile = "C:\temp\testfile.csv"
$networks = Import-CSV $csvfile
# Define the subnets and their property names as an ordered hashtable.
$subnets = [ordered] #{
'192.168.1.0' = 'ServerGW1'
'192.168.2.0' = 'ServerGW2'
'192.168.3.0' = 'WorkstationGW1'
'172.16.0.0' = 'DMZGW1'
'192.168.4.0' = 'WorkstationGW2'
}
# Add all properties of interest to the input objects, to ensure
# that Out-GridView (or other formatting cmdlets) show them all.
# Construct an array of property names, where '*' stands for the original properties...
$propNames = #('*') + [string[]] $subnets.Values
# ... and create augmented objects based on them.
$networks = $networks | Select-Object -property $propNames
$networks | % {
# See if the 'subnet' column has a value...
if ($subnet = if ($_.subnet) { ($_.subnet).split("/")[0] } else { $null }) {
# ... and, if so, see if a subnet name is defined for the part before '/' ...
if ($subnets.Contains($subnet)) {
# ... and, if so, fill the subnet-named property with the subnet address.
$_.($subnets.$subnet) = $subnet
}
}
}
Import-CSV doesn't return hashtables it returns custom objects ([pscustomobject] instances).
The code relies on the fact that, in the context of expressions, you can both assign to a variable and use the value of that assignment, such as in a conditional, as is the case here (if ($subnet = ...)).
try this, this example is dynamic, you have just to modify $hashvariable like you want (or load $hashvariable with file if you want)
$csvfile ="C:\temp\testfile.csv"
$hashArray = Import-CSV $csvfile
$hashvariable=[ordered]#{"192.168.1.0"="ServerGW1"; "192.168.2.0"="WorkstationGW1"; "192.168.3.0"="ServerGW2"; "172.16.0.1"="DMZGW1"; "192.168.5.0"="WorkstationGW2" }
$hashArray |
%{
$result=$_
$variable = if ($_.subnet -ne $null) {($_.subnet).split("/")[0]} else {""}
foreach ($key in $hashvariable.Keys)
{
$value=if ($variable -eq $key) {$key} else {""}
$result | add-member $hashvariable[$key] -NotePropertyValue $value
}
}
$hashArray | Out-GridView