Print only property names of PowerShell object - powershell

I'm trying to print out only the property names of a Powershell object.
In a script I do an Invoke-RestMethod and Write-Host ($response.result | Format-List | Out-String) gives me a nice list of the $response.result object.
Get-Member -InputObject $response.result also does not display what I want.
$response.result looks something like this: #{id=1; skip=true}.
How do I just get a list/table thats shows id, skip etc.
Many thanks!

All PowerShell objects have a hidden property PSObject that allows accessing information about the object, e.g. its properties:
$response.result.PSObject.Properties | Select-Object -Expand Name

If it's not a hashtable, you can use Get-Member to find the properties like this:
$response.result | Get-Member -MemberType Properties | Select-Object Name

If the result is just a simple 1-level hashtable, you could do something like:
(#{id=1; skip=$true}).GetEnumerator() | %{ $_.Key }
id
skip

Related

Powershell print sub-level objects in FT

I have the following generic structure:
Powershell command returns an object containing named fields and values. Some of those values are objects with another struct of names and values below them.
I want to simply print the results in a FL, but I want the sub-object values included.
The following code provides me the output I'm looking for, but I feel like I'm not doing this in a powershell-efficient way and I should be able to pipe this into a one-liner
foreach ($user in (Get-MsolUser | ?{$_.StrongAuthenticationmethods -ne $null})){
Write-host "$($user.UserPrincipalName) :: $($user.DisplayName)"
foreach($method in $user.StrongAuthenticationMethods){
write-host "`t$($method.MethodType)"
}}
I was hoping the above could be shortened to resemble the below non-functional code... is something like this possible to dump the property values when there could be a number of results between 0-X (max 4 in my case)?
Get-msolUser|?{$_.StrongAuthenticationmethods -ne $null} | select UserPrincipalName,Displayname,isLicensed,(StrongAuthenticationmethods | fl)
Use a calculated property:
Get-MsolUser |
Where-Object { $null -ne $_.StrongAuthenticationmethods } |
Select-Object UserPrincipalName, Displayname, isLicensed, #{
Name='StrongAuthenticationmethods'
Expression={ $_.StrongAuthenticationmethods.MethodType -join "`n" }
} |
Format-List
The above uses Format-List (fl), but if you prefer a tabular representation via Format-Table (ft) instead, replace | Format-List with | Format-Table -Wrap.

Compare-Object different property names

Is there a way to use Compare-Object -property, for comparing 2 properties with different names? I have something like this:
$ComparisonProperty= $ComparisonProperty | Add-Member -MemberType AliasProperty -Name Url -Value ITEM_TARGET_URI -PassThru
Compare-Object $FirstFile $SecondFile -Property Url -PassThru | Where-Object{$_.SideIndicator -eq "<="} | Out-file .\result.txt
But this gives an error:
Cannot bind argument to parameter 'InputObject' because it is null
At $ComparisonProperty
//Edit
Sample data are 2 csv files with many headers, 1 with Url header in it, another with ITEM_TARGET_URI in it. Result should be strings from file 1 that do not exist in file 2. Comparison works if i provide them with the same property names, but the whole point is to force it to compare 2 properties with different names.
To answer the actual question calculated properties or property aliases would get you what you need. You have been trying to use the latter but you need to add the property to the file object itself. Consider the two file examples
id,first_name
1,Elia
2,Nikolos
3,Bert
4,Sharleen
5,Bill
id,beginning_name
1,Elia
2,Nikolos
3,Bert
4,Mildrid
5,Bill
Notice that the headers are different. So now lets try and create the property alias. Assume that I have already imported these files as CSV's
$file2 | Add-Member -MemberType AliasProperty -Name first_name -Value beginning_name
compare-object $file1 $file2 -Property first_name
That will give you the results you were expecting. I added an alias to the second file object
You could just work with column data
Another approach to this is to drop the properties and just work with string arrays. Since I know the headers I want I can just get those columns themselves as well
$namesfromfile1 = $file1 | Select-Object -ExpandProperty first_name
$namesfromfile2 = $file2 | Select-Object -ExpandProperty beginning_name
Compare-Object $urls1 $urls2
Depending on your PS version this can also be shortened. Whether or not its simplified is up to the reader.
Compare-Object ($file1).first_name ($file2).beginning_name

How to output local administrators group membership list into HTML via powershell

I have the following powershell 1 liners that get me the results I'm looking for. Listing out the memberships of the local administrators group.
$LocalAdmins = $([ADSI]"WinNT://$Target/Administrators,group").psbase.Invoke('Members')
$Members = $LocalAdmins | foreach { $_.GetType().InvokeMember('ADspath', 'GetProperty', $null, $_, $null).Replace('WinNT://', '')} | sort -Descending
or this:
Net localgroup Administrators
When I attempt to pipe the results to ConvertTo-Html cmdlet it seems to just give me the -length property of each object in the pipeline.
Any ideas how to get to get this list to output properly in HTML?
ConvertTo-Html takes the properties of the given input object(s) and creates a HTML page to display these properties.
Since your foreach outputs just a bunch of strings, it takes the only non-standard property of string, which is Length.
If you want to see the string value in the output, too, you can try to add another property, like this
| foreach { Add-Member -InputObject $_ -NotePropertyName "Value" -NotePropertyValue "$_"; $_ } | ConvertTo-Html

Is there a way to force powershell -Export-CSV cmdlet to maintain a specific column order?

I'm new to powershell, so the script is a Frankenstein of various examples of from sites.
My question is how can I make sure that a csv file I am creating for a DataTable keeps the column order I specify?
My script does this to populate the csv headers and values like so:
...snip...
$dataTable | ForEach-Object {
$csv+=New-Object PSObject -Property #{
program_code=$_.ProgramCode;
first_name=$_.FirstName;
last_name=$_.LastName;
email=$_.email;
phone=$_.phone;
phone2=$_.otherphone;
address=$_.addr1;
address2=$_.addr2;
city=$_.city;
state=$_.state;
postal_code=$_.Zip;
country=$_.Country;
grad_year=$_.HsGradDate;
lead_date=$_.LeadDate;
lead_source=$_.LeadSource;
school_status=$_.SchoolStatus;
}
}
$csv | Export-CSV C:\scripts\NewLeads$(Get-Date -Format yyyyMMdd).csv -notype -Append
...snip...
I want the file to have to columns in the order that I specify in the script, but when I open it in notepad or excel the columns appear in a seemingly random order. Keyword being seemingly since they may have some method of ordering themselves.
In PowerShell V3, instead of:
$csv+=New-Object PSObject -Property #{
I would use:
$csv+=[pscustomobject]#{
The PowerShell V3 parser will preserve the order of the keys when you cast a hash literal to either [ordered] or [pscustomobject]. A small side benefit to this approach - it will also be faster.
If you are using V2, you'll need to skip the -Property parameter to New-Object and instead use multiple calls to Add-Member. It will look something like:
$csv+=New-Object PSObject |
Add-Member -Name program_code -Value $_.ProgramCode -MemberType NoteProperty -PassThru |
Add-Member -Name first_name -Value $_.FirstName -MemberType NoteProperty -PassThru |
...
Select the fields in the order required, then export.
$csv | select-object -property program_code,first_name,last_name,email,phone,phone2,address,address2,city,state,psotal_code,country,grad_year,lead_date,lead_source,school_status |
Export-CSV C:\scripts\NewLeads$(Get-Date -Format yyyyMMdd).csv -notype -Append
However, you may be able to short-circuit this a little. Depending on what $dataTable really is, you may (should, in most cases) be able to select directly from that object and bypass creating the collection of PSObjects. But if you need the custom headers, you'll need to use expressions in select-object (linebreaks for readability).
$dataTable| select-object #{Name="program_code";Expression={$_.ProgramCode}},`
#{Name="first_name";Expression={$_.firstname}},`
#{Name="last_name";Expression={$_.lastname}},email,phone,`
#{Name="phone2";Expression={$_.otherphone}},`
#{Name="addr1";Expression={$_.address}},`
#{Name="addr2";Expression={$_.address2}},city,state,`
#{Name="postal_code";Expression={$_.zip}},country,`
#{Name="grad_year";Expression={$_.hsgraddate}},`
#{Name="lead_date";Expression={$_.leaddate}},`
#{Name="lead_source";Expression={$_.leadsource}},`
#{Name="school_status ";Expression={$_.schoolstatus }}|
Export-CSV C:\scripts\NewLeads$(Get-Date -Format yyyyMMdd).csv -notype -Append

PowerShell Format-List from different objects in the chain

How do I output properties from parent objects in a piped chain?
For example:
get-vm | get-vmdisk | forEach {Get-VHDInfo $_.DiskPath} | Select -Property Path, ParentPath, VM.VMElementName
Basically it's the VM.VMElementName that I'm wondering about (I made up that syntax). It's not the immediate object (which would be from Get-VHDInfo) but the grandparent (from get-vm) that I want to get a value for.
You cannot get values from upstream cmdlets the way you want to. You can use foreach-object right after calling get-vm and save the value in a variable, then assign it back to the select-object as a new calculated property.
get-vm | foreach-object{
$VMElementName = $_.VMElementName
get-vmdisk | forEach {Get-VHDInfo $_.DiskPath} | Select Path,ParentPath,#{Name='VMElementName';Expression={$VMElementName}}
}