PSObject & sorting - powershell

the file ip.txt a list of IP adress
function CreateObj
{
param([string]$IP,[string]$class,[int]$number)
$Obj=New-Object PSObject
$Obj | Add-Member -Name IP -MemberType NoteProperty -Value $IP
$Obj | Add-Member -Name CLASS -MemberType NoteProperty -Value $Class
$Obj | Add-Member -Name NUMBER -MemberType NoteProperty -Value $number
return $Obj
}
$allip = get-content ip.txt
$tab=#()
foreach ($item in $allip)
{
$class = $item.substring(0,$item.lastindexof("."))
$number = [int]($item.substring($item.lastindexof(".")+1))
$tab += createobj $item $Class $number
}
$tab | sort |get-unique # <-- this fail problem of type i think ?
$tab | sort |get-unique # <-- this fail... problem of type ?
thanks

you should use the -unique parameter of sort-object cmdlet :
$tab | sort IP -unique

Related

Summing an array of Objects in Powershell

I have an array of objects that are holding integer values.
$row = new-Object PSObject # create a new object to hold its data
$row | Add-Member -Name "sheet_number" -MemberType NoteProperty -Value 1
$row | Add-Member -Name "frame_number" -MemberType NoteProperty -Value 2
$row | Add-Member -Name "sheet_height" -MemberType NoteProperty -Value 1200
$row | Add-Member -Name "frame_height" -MemberType NoteProperty -Value 1200
$row | Add-Member -Name "frame_width" -MemberType NoteProperty -Value 3300
$row | Add-Member -Name "orientation" -MemberType NoteProperty -Value 0
$frames += $row
this is in a for loop intended to iterate through several times. But the sheet_number property should only have a couple values. what I need is to sum up the values in frame_width where the sheet_number is the same.
Pseudo Code:
sheet_width = sum of frame_width where sheet number = 1
Use a combination of Where-Object, ForEach-Object, and Measure-Object:
$sum = (
$frames |
Where-Object sheet_number -eq 1 |
ForEach-Object frame_width |
Measure-Object -Sum
).Sum
To do it for all sheet numbers, additionally use Group-Object:
$arrayOfSums =
$frames |
Group-Object sheet_number |
ForEach-Object {
($_.Group.frame_width | Measure-Object -Sum).Sum
}

How I am able to pass the list of usernames on the foreach?

I am trying to make a loop from my variable $Unique_Groups but I keep getting the Get-ADObject: Variable: 'item' found in expression: $item is not defined. Maybe I did wrong on my filter side? Thank you so much in advance for the help.
$resultHOlder = #()
$data = Import-Csv -Path $path.csv
# $data = Import-Csv -Path
foreach ($item in $data) {
$table = new-object psobject
$table | Add-Member -NotePropertyName Server_Name -NotePropertyValue $item.'Server Name'
$table | Add-Member -NotePropertyName Users_Group_Belonging -NotePropertyValue $item.'User Name ( belonging to Group)'
$table | Add-Member -NotePropertyName Account_Type -NotePropertyValue $item.'Account Type'
$table | Add-Member -NotePropertyName Machine_Domain -NotePropertyValue $item.'Machine Domain'
$table | Add-Member -NotePropertyName Account_Category -NotePropertyValue $item.'Account Category'
$table | Add-Member -NotePropertyName Account_Disabled -NotePropertyValue $item.'AccountDisabled'
$table | Add-Member -NotePropertyName Last_Login_Date -NotePropertyValue $item.'Last Login Date'
$table | Add-Member -NotePropertyName Domain_Name -NotePropertyValue $item.'User Name ( belonging to Group)'.Split("\")[0]
$table | Add-Member -NotePropertyName Object_Name -NotePropertyValue $item.'User Name ( belonging to Group)'.Split("\")[1]
$table | Where-Object { !$item.'User Name ( belonging to Group)'.contains("ONEABBOTT") } | ForEach-Object { $table.Domain_Name = $null }
$resultHOlder += $table
}
# $Unique_Groups
$Unique_Groups = $resultHOlder.Object_Name | sort -Unique
# function to get the objecttype of the unique groups
function Get-ADobjectType {
$storage = #()
# $Unique_Groups | ForEach-Object {
foreach ($item in $Unique_Groups) {
# $filter = {"sAMAccountName -eq ""`$_"""}
$Membertype = Get-adobject -Filter {sammaccountName -eq $item}
$out = new-object psobject
$out | add-member noteproperty AD.localAdminMember $item
if($Membertype.Name -ne $null){$out | add-member noteproperty AD.Object $Membertype.Name}else{$out | add-member noteproperty AD.Object "NODATA"}
if($Membertype.ObjectClass -ne $null){$out | add-member noteproperty AD.Class $Membertype.ObjectClass}else{$out | add-member noteproperty AD.Class "NODATA"}
$storage += $out
$out
# }
}
return
}
Get-ADobjectType
I am expecting for a result like this:
AD.localAdminMember AD.Object AD.Class
------------------- --------- --------
user1 user1 user
user2 user2 user
group1 group1 group
group2 group2 group
Ok, you can use something like this:
function Get-ADObjectType {
[cmdletbinding()]
param(
[parameter(mandatory,valuefrompipeline)]
[string]$Name
)
begin
{
$domain = (Get-ADRootDSE).DefaultNamingContext
}
process
{
# foreach ($item in $Unique_Groups) { <= Don't need this, process block handles this for you
$filter = "(|(name=$Name)(samAccountName=$Name))"
$object = Get-ADObject -LDAPFilter $filter
if(-not $object)
{
[pscustomobject]#{
YourInput = $Name
ObjectName = "Not found in $domain"
ObjectClass = $null
}
return
}
[pscustomobject]#{
YourInput = $Name
ObjectName = $object.Name
ObjectClass = $object.objectClass
}
}
}
Use it like this if you want to process multiple users:
$resultHOlder.Object_Name | sort -Unique | Get-ADObjectType
'this.Example.User1','this.Example.User2','this.Example.User3' | Get-ADObjectType
This function will stream results, meaning, each user will be evaluated and sent to standard output.
For a unique user you can do:
Get-ADObjectType -Name this.Example.User
Edit:
I think this is something, not related to your function, but related to making your life easier in the future :)
All this:
$resultHOlder = #()
$data = Import-Csv -Path $path.csv
# $data = Import-Csv -Path
foreach ($item in $data) {
$table = new-object psobject
$table | Add-Member -NotePropertyName Server_Name -NotePropertyValue $item.'Server Name'
$table | Add-Member -NotePropertyName Users_Group_Belonging -NotePropertyValue $item.'User Name ( belonging to Group)'
$table | Add-Member -NotePropertyName Account_Type -NotePropertyValue $item.'Account Type'
...
...
...
Can be replaced with this:
$header = #(
'YourHeaderName 1'
'YourHeaderName 2'
'YourHeaderName 3'
'YourHeaderName 4'
'YourHeaderName 5'
)
$csv = Get-Content -Path $path |
Select-Object -Skip 1 |
ConvertFrom-Csv -Header $header

Get PSObject array size or count

I create an array like this:
$Array = #()
$Item = New-Object PSObject
$Item | Add-Member -Type NoteProperty -Name item1 -Value test
$Item | Add-Member -Type NoteProperty -Name item2 -Value test
$Array += $Item
Now I want to add a check to determine if $Item is empty before adding it in $Array. How can I get the member count of $Item ?
I tried stuff like :
$Item.count
$Item.length
#($Item).count
($Item | Measure).count
($Item | Get-Member).count
$Item.psobject.members.count
But none of them gives me the actual member count.
You can use the hidden .PsObject.Properties to either check for
$Item.PSobject.Properties.Value.count or
$Item.PSobject.Properties.Names.count
$Item = New-Object PSObject
$Item.Psobject.Properties.value.count
0
$Item | Add-Member -Type NoteProperty -Name item1 -Value test
$Item.Psobject.Properties.value.count
1
$Item | Add-Member -Type NoteProperty -Name item2 -Value test
$Item.Psobject.Properties.value.count
2
The correct way is:
($Item|Get-Member -Type NoteProperty).count
The following Get_ItemCount function could help:
Function Get_ItemCount {
$aux = $($item | Get-Member -MemberType NoteProperty)
if ( $aux -eq $null ) {
0
} elseif ( $aux -is [PSCustomObject] ) {
1
} else {
$aux.Count
}
}
$Item = New-Object PSObject
Get_ItemCount # 0
$Item | Add-Member -Type NoteProperty -Name item1 -Value test
Get_ItemCount # 1
$Item | Add-Member -Type NoteProperty -Name item2 -Value test
Get_ItemCount # 2
Output
PS D:\PShell> .\SO\55064810.ps1
0
1
2
PS D:\PShell>

Selecting from objects within objects

I have an array of information in Powershell that is comprised of objects within objects. It goes down 4 objects deep. Is there a way to select a property from the bottom most object while remaining at the top level? Does this make sense what I am asking?
$result
active : active
security : #{waf=; acls=}
sealloaction :
siteDualFactorSettings : #{enabled=False; version=0}
login_protect : #{enabled=False; url_patterns=System.Object[]}
performance_configuration : #{advanced_caching_rules=; acceleration_level=standard; cache300x=False; cache_headers=System.Object[]}
$result.security
waf acls
--- ----
#{rules=System.Object[]} #{rules=System.Object[]}
$result.security.waf
rules
-----
{#{action=api.threats.action.block_request; action_text=Block; id=api.threats.sql_injection; name=SQL Injection}, #{action=api.threats.action.alert; action_text=Alert Only;}
To produce a mixed main/nested level selection:
foreach on the main array
select of the nested stuff + calculated properties to reference the iterated main array element
$results | ForEach {
$r = $_
$r.security.waf.rules | select *, #{N='domain'; E={$r.domain}}
}
Or as a one-liner:
$results | %{ $r = $_; $r.security.waf.rules | select *, #{N='domain'; E={$r.domain}} }
$myArray | where { $_.x.y.z -eq 'something' }
which is functionally equivalent to
foreach ($object in $myArray)
{
if ($object.x.y.z -eq 'something')
{
$object # Writes $object to the output stream
}
}
The easier way should be with $result | select ${L='label';E={$_.security.waf}} then you drill down to where you want.
For example:
$obj1_child = New-Object -TypeName psobject
$obj1_child | add-member -Name obj1_child -MemberType NoteProperty -Value "obj1_child"
$obj1_child | add-member -Name value1 -MemberType NoteProperty -Value "child_value1"
$obj1 = New-Object -TypeName psobject
$obj1 | add-member -Name obj1 -MemberType NoteProperty -Value "obj1"
$obj1 | add-member -Name child -MemberType NoteProperty -Value $obj1_child
$obj2 = New-Object -TypeName psobject
$obj2 | add-member -Name value1 -MemberType NoteProperty -Value "value1"
$parentObj = New-Object -TypeName psobject
$parentObj | Add-Member -MemberType NoteProperty -name string -value "parentObject"
$parentObj | Add-Member -MemberType NoteProperty -name OBJ1 -value $obj1
$parentObj | Add-Member -MemberType NoteProperty -name OBJ2 -value $obj2
$parentObj | select string,obj2, #{L='value of obj1 child';E={$_.obj1.child.value1}}
I create a $parentObj inside there's a string, and two objects ($obj1,$obj2), and inside $obj1 there's another object ($obj1_child). Now I want the string from $parentObj and the last string from $obj1_child this should work:
$parentObj | select string, #{L='value of obj1 child';E={$_.obj1.child.value1}}
Output:
>> $parentObj | select string, #{L='value of obj1 child';E={$_.obj1.child.value1}}
string value of obj1 child
------ -------------------
parentObject child_value1
Not sure if it's what you want. but it was what I was looking for when landed here, so may help someone else.
Reference:
https://devblogs.microsoft.com/scripting/access-objects-inside-other-objects-in-powershell-pipeline/
Two ways to do the same thing
$x = [PSCustomObject]#{
active = 'active';
security = [PSCustomObject]#{
waf = [PSCustomObject]#{
rules = #(
[PSCustomObject]#{
action='api.threats.action.block_request';
action_text='Block';
id='api.threats.sql_injection';
name='SQL Injection'},
[PSCustomObject]#{
action='api.threats.action.alert';
action_text='Alert Only';}
)
}
acls = [PSCustomObject]#{
rules = #(
[PSCustomObject]#{
action='api.threats.action.block_request';
action_text='Block';
id='api.threats.sql_injection';
name='SQL Injection'},
[PSCustomObject]#{
action='api.threats.action.alert';
action_text='Alert Only';}
)
}
}
}
$x.security.waf.rules | select *, #{name='domain'; ex={'foo'}}
$x | select -ExpandProperty security | select -ExpandProperty waf | select -ExpandProperty rules | select *, #{name='domain'; ex={'foo'}}

Copy entire list using Powershell CSOM sharepoint

I need to export an entire list as a .csv file. I actually have this code which works great but I need to write each column I want to export:
$listTitle = "Example"
$list = $ctx.get_web().get_lists().getByTitle($listTitle);
$query = New-Object Microsoft.SharePoint.Client.CamlQuery;
$query.ViewXml = "<View><Query><Where><Geq><FieldRef Name='ID' /><Value Type='Counter'>1</Value></Geq></Where></Query></View>"
$listItems = $list.GetItems($query);
$ctx.Load($listItems);
$ctx.ExecuteQuery();
$tableau =#();
foreach ($listItem in $listItems)
{
$result = new-object psobject
$result | Add-Member -MemberType noteproperty -Name Title -value $listItem['Title'];
$result | Add-Member -MemberType noteproperty -Name Description -value $listItem['Description'];
$result | Add-Member -MemberType noteproperty -Name Age -value $listItem['Age'];
$result | Add-Member -MemberType noteproperty -Name Sexe -value $listItem['Sexe'];
$tableau += $result;
}
$CsvName2 = "Export_"+$ListTitle.replace(' ','_')+".csv"
$tableau | export-csv $CsvName2 -notype;
The part I want to improve is the foreach loop:
foreach ($listItem in $listItems)
{
$result = new-object psobject
$result | Add-Member -MemberType noteproperty -Name Title -value $listItem['Title'];
$result | Add-Member -MemberType noteproperty -Name Description -value $listItem['Description'];
$result | Add-Member -MemberType noteproperty -Name Age -value $listItem['Age'];
$result | Add-Member -MemberType noteproperty -Name Sexe -value $listItem['Sexe'];
$tableau += $result;
}
I want the script collects all columns but I don't know how to do it...
I got this advice: Replace my loop with:
foreach ($listItem in $listItems)
{
$result = new-object psobject
foreach ($field in $listItem.Fields)
{
if ($field.Hidden -eq $false)
{
$result | Add-Member -MemberType noteproperty -Name $field.Title -value $listItem[$field.InternalName];
}
}
$tableau += $result;
}
But all I got is a blank file. I don't really understand structure of list/filed items.
Thanks for your help.