I am trying to list the Azure resource groups based on only the locations available in vnet locations. Here is my code.
$AllVnet=Get-AzVirtualNetwork
$SelectVnet=$AllVnet | Select-Object -Property Name,ResourceGroupName,Location
$vnetloc=$SelectVnet.Location
$ResourceGroupList=#()
foreach($loc in $vnetloc)
{
$ResourceGroup=Get-AzResourceGroup -Location $loc
$Name=$ResourceGroup.ResourceGroupName
$Loc=$ResourceGroup.Location
$VMObject = New-Object PSObject
$VMObject | Add-Member -MemberType NoteProperty -Name "Name" -Value $Name
$VMObject | Add-Member -MemberType NoteProperty -Name "Location" -Value $Loc
$ResourceGroupList += $VMObject
}
$ResourceGroupList
It returns the result in the below format
Name Location
---- --------
AZRWUSRG1 westus
{NWRG, AZREUS####, AZREU###, AZREUSLSSTO###} {eastus, eastus, eastus, eastus…}
But I want in this format
Name Location
---- --------
AZRWUSRG1 westus
NWRG eastus
AZREUS#### eastus
AZREUSLSSTO### eastus
How can I achieve that? Can anyone please help.
Get-AzResourceGroup can return multiple objects of type PSResourceGroup. In this case $ResourceGroup will be an array.
$Name=$ResourceGroup.ResourceGroupName
The above code lets PowerShell create an array by collecting the value of the property ResourceGroupName from all elements of the array $ResourceGroup. This is why you get output like {NWRG, AZREUS####, AZREU###, AZREUSLSSTO###}.
The code can be fixed and greatly simplified like this:
$AllVnet=Get-AzVirtualNetwork
$SelectVnet=$AllVnet | Select-Object -Property Name,ResourceGroupName,Location
$vnetloc=$SelectVnet.Location
$ResourceGroupList = foreach($loc in $vnetloc)
{
Get-AzResourceGroup -Location $loc | Select-Object Name, Location
}
Using Select-Object we create a new object for each PSResourceGroup element that is returned from Get-AzResourceGroup, containing only the given properties.
Since we have assigned the foreach output to a variable, PowerShell automatically captures all output from the loop body in the variable, which will be an array when there are more than one elements.
Related
I am trying to parse parameters of a Graph command to get every value and attribute name. The reason would be to use Compare-Object between the current state of an object and bodyparams added as JSON or an array in Powershell.
Or even create a simple function to compare any of the old params with the JSON for any change, and create a parms with the differences.
The conceptual idea would be to have a template for any modification without using the commands, the old object's params, to compare with a new set of params from the diff.
So far, I managed to do this :
Get-MgGroup -GroupId $GroupId | Select-Object * |Convertto-Json
Which returns :
{
"AcceptedSenders": null,
"AllowExternalSenders": null,
"AppRoleAssignments": null,
"AssignedLabels": null,
"AssignedLicenses": null,
(The whole JSON is too long to be put here, and it would be pointless. It's just attributes and objects)
Which is what I'd want. But I would want to do the same with the object itself
Definition is where the values are since this command:
Get-MgGroup -GroupId $GroupId | Select-Object * | Get-Member -MemberType NoteProperty
Returns this :
Name MemberType Definition
---- ---------- ----------
AcceptedSenders NoteProperty object AcceptedSenders=null
AdditionalProperties NoteProperty Dictionary[string,Object] AdditionalProperties=System.Collections.Generic.Dictionary`2[System.String,System.Object]
AllowExternalSenders NoteProperty object AllowExternalSenders=null
AppRoleAssignments NoteProperty object AppRoleAssignments=null
AssignedLabels NoteProperty object AssignedLabels=null
AssignedLicenses NoteProperty object AssignedLicenses=null
AutoSubscribeNewMembers NoteProperty object AutoSubscribeNewMembers=null
Calendar NoteProperty MicrosoftGraphCalendar Calendar=Microsoft.Graph.PowerShell.Models.MicrosoftGraphCalendar
CalendarView NoteProperty object CalendarView=null
Classification NoteProperty object Classification=null
Conversations NoteProperty object Conversations=null
CreatedDateTime NoteProperty datetime CreatedDateTime=04/09/2022 05:48:57
CreatedOnBehalfOf NoteProperty MicrosoftGraphDirectoryObject CreatedOnBehalfOf=Microsoft.Graph.PowerShell.Models.MicrosoftGraphDirectoryObject
DeletedDateTime NoteProperty objec
As you can see, not every value is null or a string, so I cannot just fill an empty object with an iteration of the name with null on it.
In simple terms, I would like to get from the cmd's any "NoteProperty" : the name, the type, and the value.
I figure it might be hard to grasp without context, I wrote a draft on kroki
enter image description here
The idea would have a model for any future change, but I wouldn't want to change it manually every time.
Edit :
I actuall went further and maybe that'll be more evident with the function :
function Compare-Attributes {
Get-MgGroup -GroupId $GroupId | Select-Object -Property * | ConvertTo-Json -Compress | Out-file -FilePath 'C:\Users\Currentusr\Currentdir\BodyParams.JSON'
### I change some values
$old_parms = #(Get-MgGroup -GroupId $GroupId | Select-Object -Property * | ConvertTo-Json )
$new_parms = #(Get-Content 'C:\Users\Currentusr\Currentdir\BodyParams.JSON' | Convertfrom-Json )
$new_parms = #(Get-Content 'C:\Users\YassinBousaadi\projects\Ansible\Ansible_Modules\BodyParams.JSON' | Convertfrom-Json |
Edit-LeafProperty -PassThru { if ($null -eq $_.Value) { $_.Value = 'null' } } | ConvertTo-Json)
$old_parms_obj = #( $old_parms| ConvertFrom-Json)
$new_parms_obj = #( $new_parms | ConvertFrom-Json)
echo $new_parms_obj
Compare-Object -ReferenceObject $old_parms_obj `
-DifferenceObject $new_parms_obj `
-IncludeEqual `
What it returns is actually not half bad :
InputObject
-----------
#{AcceptedSenders=null; AllowExternalSenders=null; AppRoleAssignments=null; AssignedLabels=null; AssignedLicenses=null; AutoSubscribeNewMembers=null; Calendar=; CalendarView=null; Classification=null; Conversations=null; CreatedDateTime=04/09/2022 05:48:57; CreatedOnB...
I changed the AcceptedSenders attribute as true in the JSON in between, so that value should show. but that'll be the one to show, since it's the only one that's changed, right ? I even went and changed every null value to actual null as strings in the JSON because it would otherwise return empty values
I got an $Object with a ton of properties which look like this:
IsSynchronized : { False, False }
What I want is to do something like :
$Object | Export-Csv C:\Test\Merge.csv -Delimiter ';'
To get a CSV containing :
IsSynchronized
--------------
False
False
But as expected I get
IsSynchronized
---------------
System.Object[]
Is there a good way to get a ton of the object's properties in a .CSV ?
I have 6 .csv files with values and I try to add them in to one big .csv for further processing.
Edit:
I asked about this Topic yesterday but i need to make more clear what i want.
I create a PSCustomObject and fill it with Arrays:
$Object = New-Object -TypeName PSCustomObject
$Object | add-member -membertype NoteProperty -name "CPUHost" -value $global:CPUHost
$Object | add-member -membertype NoteProperty -name "NumCpu" -value $global:NumCpu
$Object | add-member -membertype NoteProperty -name "MemoryMB" -value $global:MemoryMB
$Object | add-member -membertype NoteProperty -name "CPU Usage (Average), Mhz" -value $global:CPUUsageAverageMhz
$Object | add-member -membertype NoteProperty -name "CPU Usage (Average), %" -value $global:CPUUsageAverage
$Object | add-member -membertype NoteProperty -name "Memory Usage (Average), %" -value $global:MemoryUsageAverage
$Object | add-member -membertype NoteProperty -name "Network Usage (Average), KBps" -value $global:NetworkUsageAverageKBps
$Object | add-member -membertype NoteProperty -name "Disk Usage (Average), KBps" -value $global:DiskUsageAverageKBps
...
All of these Global Variables are Arrays because i never know how many Values i get in the first place.
They are filled by lopping through 6 CSV Files i will allways get.
After running this bit i will have a Object looking like this:
CPUHost : {xxxx}
NumCpu : {20}
MemoryMB : {36094}
CPU Usage (Average), Mhz : {3914,33}
CPU Usage (Average), % : {8,91}
Memory Usage (Average), % : {70,17}
Network Usage (Average), KBps : {439,68}
Disk Usage (Average), KBps : {1994,93}
...
What i want is to Export that in to a CSV Displayed like :
CPUHost NumCPU MemoryMb CPUUsage ...
------- ------ -------- ---------
xxxx 20 36094 3914
33
With every Value in its own Cell.
What i get is instead of the values : System.Type.[] which is technically correct but not what i need.
I allready tryed to -join the values but that will leave me with the values in the same cell
You state that you have one object with multiple properties like what was posted. I assume you have an object that looks like the following:
IsSynchronized Property2 Property3
-------------- --------- ---------
{False, False} {1, 2, 3} {string1, string2, string3, string4}
You could do the following:
$loopmax = $object[0].psobject.properties |% {($_.Value | measure-object).Count} | Sort -desc | Select -First 1
$newobject = for ($i = 0; $i -lt $loopmax; $i++) {
$hash = [ordered]#{}
foreach ($p in $object[0].psobject.properties.name) {
$hash[$p] = $object.$p[$i]
}
[pscustomobject]$hash
}
$newobject | convertto-csv -notype
This doesn't seem wise to do. CSV isn't very good for representing or storing rich or hierarchical objects. The problem is even worse when the property is an object, in your case it's a flat array. You can output as you suggest / request, and other answers have demonstrated:
IsSynchronized
--------------
False
False
However, this disrupts the property's relationship to the other properties. If you have other types like [String] & [Int], or even varying numbers of elements in array typed properties things are going to get weird quickly!
If you must stick with CSV you can sub-delimit the field. A great example of this is Exchange Message Tracking logs. They are CSV files delimited on the typical ",", but the recipients field is sub-delimited on a ";".
An example in code might look something like this:
$Object =
[PSCustomObject]#{
Prop1 = "one"
Prop2 = "two"
Arr1 = #( 1,2,3,4 )
}
$Object |
Select-Object Prop1, Prop2,
#{ Name = 'Arr1'; Expression = {$_.Arr1 -join "," } } |
ConvertTo-Csv -Delimiter ";"
Results:
"Prop1";"Prop2";"Arr1"
"one";"two";"1,2,3,4"
Note: To use full fidelity data in a later process would require appropriate handling on input. However, if you follow other solutions and said weirdness occurs you'll be left with a similar issue; having to handle on the input side everywhere you intend to use that data.
Given CSV's shortcomings JSON may be a better choice to store & reuse full fidelity objects. Export/Import CliXML are interesting for this.
To answer the literal question asked (although I'm not sure that's what the OP actually wants)...
If you have a single object with a property that contains an array of values, you can expand them out into a new array and then convert that to csv as follows:
$obj = new-object psobject -Property #{
"IsSynchronized" = #( $false, $false )
}
$obj
# IsSynchronized
# --------------
# {False, False}
$data = $obj.IsSynchronized | foreach-object {
new-object pscustomobject -Property #{ "IsSynchronized" = $_ }
}
$csv = $data | ConvertTo-Csv -NoTypeInformation
$csv
# "IsSynchronized"
# "False"
# "False"
I'm a newbie of powershell, I'm starting right now to look at objects, etc.
I'm creating an object in this way:
$myObject = [PSCustomObject]#{
ComputerName = "abc"
Data = "xxx"
}
If I then print $myObject what i get is:
ComputerName Data
------------ ----
abc xxx
And everything is ok, now I want to add a property to that object, and I saw (tell me if i'm wrong) that I can do it in 2 ways: with add-member and with select-object
For example with add-member what I did was:
$myObject | Add-member -NotePropertyName Level -NotePropertyValue Highest
Instead with Select-object I did:
$myobject = 2 (cause i want to add 2 properties, is it right?) | Select-Object -Property Level, Privilege
$myobject.Level = "High"
$myobject.Privilege = "Elevated"
Now if I run $myobject I still only get:
ComputerName Data
------------ ----
abc xxx
What should I do to see all the data, even the one that I added later?
Can I directly add the values to the properties added through Select-Object?
Thanks
You can use the Add-Member method on a PsCustomObject.
$myObject = [PSCustomObject]#{
ComputerName = "abc"
Data = "xxx"
}
$myObject | Add-Member -NotePropertyName Level -NotePropertyValue High
$myObject | Add-Member Privilege Elevated
$myObject
#Output looks like,
ComputerName Data Level Privilege
------------ ---- ----- ---------
abc xxx High Elevated
Update
Not sure at the moment why but will elaborate on it ...
If you print the Pscustomobject and then run the add-member, they seem to be ignored. If you create a hashtable, update it and then convert to PsObject, it works. Following is an example of that hashtable
$myObject = #{
ComputerName = "abc"
Data = "xxx"
}
$myObject | ft
$myObject.Add("Level", "high")
$myObject.Add("Privilege", "Elevated")
[pscustomobject] $myObject | ft
What I found
When you print $myObject then add the data, the data is added but not displayed. This is due to some internal mechanism, unknown to me, that continues to use the same headers from previous command.
If you notice, the data is printed twice under the same heading. If you want to see the differences before and after, pipe it to format-list or format-table to use a different output stream each time.
$myObject = [PSCustomObject]#{
ComputerName = "abc"
Data = "xxx"
}
$myObject | ft
$myObject | Add-Member -NotePropertyName Level -NotePropertyValue High -Force
$myObject | Add-Member Privilege Elevated
$myObject | ft
You can use either Add-Member or Select-Object. Withstanding the advantages or disadvantages in different situations I just want to throw in the Select-Object example. Just so you have both methods:
This example will echo the object with the selected properties:
$myObject |
Select-Object *,
#{Name = 'Level'; Expression = { 'High' } },
#{Name = 'Privilege'; Expression = { 'Elevated' } }
If you want to save the new properties back to the object variable you'll have to reassign like below:
$myObject = $myObject |
Select-Object *,
#{Name = 'Level'; Expression = { 'High' } },
#{Name = 'Privilege'; Expression = { 'Elevated' } }
PowerShell allows you to provide a hash table to define the new properties. You'll note it looks fairly similar to the hash you used to create the object. Typically the expression would leverage the $_ syntax to calculate the property's value. You will often here these referred to as calculated properties.
I have a variable stored as a System.Array displayed as;
Site : https://value.sharepoint.com/
Email : value#value.co.uk
DisplayName : value
UniqueId : value
AcceptedAs : value#value.co.uk
WhenCreated : 24/01/2019 06:02:45
InvitedBy : value_value.co.uk#ext##value.onmicrosoft.com
When I try to export this variable as a file it shows in the same format. As this is not in the correct structure for a table (shown below) I am unable to use this data when I try to use it in Power BI.
Site Email ect
---- ---- ----
https://value.sharepoint.com/ value#value.co.uk ect
I need to get my data into the structure shown above. I have tried;
$Test = New-Object -TypeName PSObject -Property $ExternalUsers
However this results in the following error;
New-Object : Cannot convert 'System.Object[]' to the type 'System.Collections.IDictionary' required by parameter 'Property'. Specified method is not supported.
I then tried to loop through all of the items in the array and then create an object for each item, before adding it to a "Master Object";
foreach($var in $ExternalUsers){
$Test = New-Object -TypeName PSObject -Property $ExternalUsers
$Test | Add-Member -MemberType NoteProperty -Name Site -Value $var.Site
$Test | Add-Member -MemberType NoteProperty -Name Email -Value $var.Email
$TestObject += $Test
}
This got each item into the correct structure but when I tried to add all the items back into the one variable I got the error;
Method invocation failed because [System.Management.Automation.PSObject] does not contain a method named 'op_Addition'.
Any ideas how I could get around this?
To me it looks like you have an array (System.Object[]) containing PSObjects with the properties Site, Email etc.
A structure like that is ideal for exporting to CSV file, which you can then import in a spreadsheed application like Excel for instance.
For that you use the cmdlet Export-Csv like this:
$ExternalUsers | Export-Csv -Path 'PATH AND FILENAME FOR THE OUTPUT CSV FILE' -NoTypeInformation
If the output you show is complete, it seems there is only one element in the array. You can check this by looking at $ExternalUsers.Count.
I'm not quite sure what you mean by "As this is not in the correct structure for a table", because you can quite easily display it as table using
$ExternalUsers | Format-Table -AutoSize
Output on console window:
Site Email DisplayName UniqueId AcceptedAs WhenCreated InvitedBy
---- ----- ----------- -------- ---------- ----------- ---------
https://value.sharepoint.com/ value#value.co.uk value value value#value.co.uk 24/01/2019 06:02:45 value_value.co.uk#ext##value.onmicrosoft.com
If what you want is less properties, just loop through the array and select the properties you want to keep from the objects in it:
$Shortened = $ExternalUsers | ForEach-Object {
$_ | Select-Object Site, Email
}
$Shortened | Format-Table -AutoSize
Will produce:
Site Email
---- -----
https://value.sharepoint.com/ value#value.co.uk
I'm not into Power BI, but remember that the Format-Table cmdlet is for display purposes on console ONLY.
It does NOT provide anything else but a view on the data.
Hope this helps
use:
$TestObject = #()
and no need to specify (-Property $ExternalUsers)
$Test = New-Object -TypeName PSObject
I have been tasked to get the MMS term sets that are being used based on terms(not with null value of MMS column in the list's items ) in all the sites so that only those MMS terms sets can get migrated to the other sharepoint environment. On a base level I'm using below script
$FieldCollection= (Get-SPWeb https:/sharepoint.com/sites/pssl/mgmt).Lists.Fields
$MetadataField = New-Object psobject
$MetadataField | Add-Member -MemberType NoteProperty -Name "ParentListUrl" -value ""
$MetadataField | Add-Member -MemberType NoteProperty -Name "ParentListTitle" -value ""
$MetadataField | Add-Member -MemberType NoteProperty -Name "FieldTitle" -value ""
$MetadataField | Add-Member -MemberType NoteProperty -Name "FieldId" -value ""
$matches = #();
foreach($field in $FieldCollection)
{
if($field.GetType().Name -ne "TaxonomyField"){
continue;
}
#if($field.TermSetId.ToString() -ne $TermSet.Id.ToString()){continue;}
$tf = $MetadataField | Select-Object *;
$tf.ParentListUrl = $field.ParentList.ParentWeb.Url;
$tf.ParentListTitle = $field.ParentList.Title;
$tf.FieldTitle = $field.Title;
$tf.FieldId = $field.ID;
$matches += $tf;
}
return $matches;
but it returns only managed metadata columns defined in the list, but not they are being used in the list. Can anybody help me to achieve the task.
I'm not an expert in Sharepoint API, but I'm trying to understand what the problem is to help you and I can't.
I notice that you create an object $MetadataField before a loop, then kind of create a replica $MetadataField | Select-Object * and then add in a array.
As you say, the returned objects should only have the columns of ParentListUrl,ParentListTitle,FieldTitle and FieldId which is what I expect from the sample above. Can you elaborate more on what you are looking for? Maybe update the entire function into your question and post your returned expectation. this way I can try to help you out.
Btw, the ; is not required and you should create a new instance of the object within the loop. You can use the same method or first create a hash key that drives the properties of a custom object. For example in your loop adjust the following.
$hash=#{
Property1="Value1"
Property2="Value2"
}
New-Object -Type PSObject -Property $hash
Also if you function returns directly each found item without extra processing, then you can skip adding them in an array and just write in the output like I do in my example. To make it more clear, if I would put a loop around my example in a function and execute, then I would get a recordset with custom object with Property1 and Property2