If e.g. Get-NetTCPConnection command returns OwningProcess ID is it possible to create a one-liner which adds another columns which expands the ID to ProcessName as returned by Get-Process -Id?
Yes, using calculated expressions. See example 10 on the Select-Object documentation
Get-NetTCPConnection | select OwningProcess,#{n="ProcessName";e={Get-Process -Id $_.OwningProcess | select -ExpandProperty ProcessName}}
Edit
Is there a way to tell Select-Object to keep all properties without explicitly listing them so that the calculated expression appears in addition to what is printed by default?
Yes but it's a a lot more convoluted than it should be. The crux of it is (as you may already know) "all properties" and "printed by default" are two different things. You can see this by comparing Get-NetTCPConnection to Get-NetTCPConnection | select *
So to get all properties + the calculated property it would be:
Get-NetTCPConnection | select *,#{n="ProcessName";e={Get-Process -Id $_.OwningProcess | select -Expand ProcessName}}
To get the default properties + the calculated property (*sigh*):
# this is from Get-NetTCPConnection | Get-Member
$typeName = 'Microsoft.Management.Infrastructure.CimInstance#ROOT/StandardCimv2/MSFT_NetTCPConnection'
# export format data for this type
Get-FormatData -TypeName $typeName | Export-FormatData -IncludeScriptBlock -Path $env:TEMP\formatdata.ps1xml
# open the ps1xml in editor of choice C:\Users\<user>\AppData\Local\Temp\formatdata.ps1xml
# Add under TableHeaders
<TableColumnHeader>
<Width>14</Width>
</TableColumnHeader>
# Add under TableColumnItems
<TableColumnItem>
<ScriptBlock>
Get-Process -Id $_.OwningProcess | select -ExpandProperty ProcessName
</ScriptBlock>
</TableColumnItem>
# save ps1xml
# update format data
Update-FormatData -PrependPath $env:TEMP\formatdata.ps1xml
The above is limited to the current session. You can add Update-FormatData to your profile so it's done every time you start a session. Or use the scorched Earth approach and modify the source format file (not recommended, I didn't try it) located at C:\Windows\system32\WindowsPowerShell\v1.0\Modules\NetTCPIP\Tcpip.Format.ps1xml.
How to find this location:
Get-Command Get-NetTCPConnection | select -Expand Module | select -Expand ExportedFormatFiles
Related: Using the PowerShell formatting system to your advantage, about_format.ps1xml, Loading and Exporting Formatting Data, Get-FormatData, Update-FormatData
Related
I need to check if this checkbox is enabled or disabled:
Is there anyway i can check this with powershell, because there something like 1400 shares I need to check?
Any help is welcome!
The cmdlet Get-SmbShare returns objects with losts of useful properties. One of which is called CachingMode.
To report on shares where the CachingMode is set to 'Manual' for instance, you can do
# as example only output on screen
Get-SmbShare | Where-Object {$_.CachingMode -eq 'Manual'} | Format-Table -Property Name, CachingMode
If you want to save this data to csv , remove the Format-Table cmd and do
Get-SmbShare | Where-Object {$_.CachingMode -eq 'Manual'} |
Select-Object Name,CachingMode |
Export-Csv -Path 'X"\Somewhere\ShareCaching.csv' -NoTypeInformation
In a nutshell I'm trying to get what would be the output of this command to run.
Get-Process | Format-Table | sort-object Handles
Yes, I know you usually sort BEFORE Format-Table, but in this case I've created a hash-table within the Format-Table command that needs to be sorted. The problem is, there is no way to sort with Format-Table that I can figure out.
I also considered trying to output the FT to CSV and then massaging it but that didn't work for me either.
I'm expecting to get a sorted table.
I've created a hash-table within the Format-Table command that needs to be sorted
By definition, you can not output a hashtable via any of the -Format-* cmdlets:
Format-* cmdlets emit output objects whose sole purpose is to provide formatting instructions to PowerShell's for-display output-formatting system. In short: only ever use Format-* cmdlets to format data for display, never for subsequent programmatic processing - see this answer for more information.
Assuming you've used calculated properties, with Format-Table, use them with Select-Object instead, which produces data output, namely in the form of [pscustomobject] instances whose properties you can sort by, via Sort-Object.
For instance, the following creates custom objects with .Name and .MemUse properties and sorts by the latter, then outputs the top 10 results:
Get-Process |
Select-Object Name, #{ Name = 'MemUse'; Expression = 'WorkingSet64' } |
Sort-Object -Descending MemUse |
Select-Object -First 10
Inverting the logic and letting Sort-Object operate on the original objects output by Get-Process is more efficient:
Get-Process |
Sort-Object -Descending WorkingSet64 |
Select-Object -First 10 |
Select-Object Name, #{ Name = 'MemUse'; Expression = 'WorkingSet64' }
If you only care about for-display output, you can replace Select-Object Name, ... with Format-Table -Name, ... or Format-List -Name, ..., which illustrates an important point: Format-* calls should generally only come last in a pipeline.
I have a script that creates several jobs and stores two simple values in the jobs.
Start-Job -ScriptBlock {param ([string]$compip) tnc $compip | select RemoteAddress,PingSucceeded -WarningAction SilentlyContinue} -ArgumentList $compip
This works fine. What I would like to know is how can I store the following code into a variable?
Get-Job | Receive-Job | sort RemoteAddress | FT
I have tried this, but it does not work as I thought it would:
$pcs = Get-Job | Receive-Job | sort RemoteAddress | FT
$pcs.RemoteAddress
Am I going at this the wrong way? I would like to store the data from the get-job command above to use the values later in the script. I assumed it would work because the output looks correct:
Command:
Get-Job | Receive-Job | sort RemoteAddress | FT
Output:
RemoteAddress PingSucceeded
------------- -------------
192.168.0.163 True
192.168.0.101 False
192.168.0.2 False
192.168.0.251 True
Problem with Format-cmdlets
The issue here is your use of FT which is an alias for Format-Table. These Format- cmdlets are designed for console/screen output only. There are many things you can do with them to tailor that output but in every case PowerShell needs to massage the data in order to be able to do so. This includes breaking down to the passed objects into groups of different objects...
Microsoft.PowerShell.Commands.Internal.Format.FormatEndData
Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData
Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
Microsoft.PowerShell.Commands.Internal.Format.GroupEndData
Microsoft.PowerShell.Commands.Internal.Format.GroupStartData
The above data types were extract from running this code.
Get-ChildItem c:\temp | Format-Table | Get-Member
So you no longer have the System.IO.FileInfo and System.IO.DirectoryInfo objects that you would normally get from Get-ChildItem
Another large issue comes from Format-cmdlets nature to truncated data, like arrays with a large numbers of elements or long strings, to make as much fit on screen. In the case of arrays, this is due to the preference variable $FormatEnumerationLimit which is commonly defaulted to 4.
Ten Numbers
-----------
{1, 2, 3, 4...}
These, and other, limitations can all be mitigated with cmdlet switches like -AutoSize and -HideTableHeaders, out-string -width, etc. That does not matter however because...
Solution
Good news is the solution is very simple. Stop using them for anything other than console output. Using my earlier example:
Saving results in a variable?: $result = Get-ChildItem C:\temp
Exporting Data: Get-ChildItem C:\temp | Export-CSV $path -NoTypeInformation. Other Export-cmdlets could be preferred here like Export-CLIXml for complex objects when you want to store them for use elsewhere. If you are just looking for something pretty to include in your output then consider ConvertTo-HTML instead.
Extracting individual properties?: Just use Select-Object. $result | Select prop1, prop2. You can also expand your property selection to just get the strings or string array with -ExpandProperty: $result | Select -ExpandProperty prop1
Performing inline calculations with said properties?: Use calculated expression just as you would with the Format-Cmdlets. $result | Select prop1, #{Name="prop2";Expression={$_.prop2 * 3}
Potential Acceptable Use
Some prefer the output for use in emails and for recording statistics. While it is integral to keep data in its more easily used format for later use. However if you really need that data keep in mind that you are not working with the object your originally had anymore.
So if you needed your data in a table format but stored as a string then consider Out-String
$body = Get-ChildItem c:\temp | Format-Table | Out-String
but remember that Format-Table will play with object output in order to get it to display on screen (truncated array properties and long strings). Really.. if you wanted it nice and formatted then you should just use ConvertTo-HTML.
Point is you almost never need to keep the data from Format-Table. There is almost always a better way.
This is regarding AWS Certificate manager:
Get-ACMCertificatelist | Get-ACMCertificateDetail | Select -ExpandProperty renewalsummary | Where-object {$_.renewalStatus -ne "Success"}
Following is the output and I want to remove those curly brackets:
DomainValidationOptions RenewalStatus
----------------------- -------------
{Certificate1} PENDING_AUTO_RENEWAL
{certificate2} PENDING_AUTO_RENEWAL
The object in question is actually giving you an array for the DomainValidationOptions part, which can contain more than one value.
| Select #{n="DomainValidationOptions";e={($_.DomainValidationOptions -join ",")}},RenewalStatus
putting this on the end of your query will replace the DomainValidationOptions with a comma-separated string instead of an array, but keep the name, in cases where there's only one option this technically just converts it to a string.
Those are automatically added when converting a collection to a string in the formatting cmdlets. You can format the objects yourself to get rid of them.
You can specify calculated properties for each of the properties of DomainValidationOptions that you want to drill down into.
Step 1) Discover Properties
Pipe DomainValidationOptions to Get-Member -MemberType Property to see what properties you're going to be working with:
Get-ACMCertificateList |
Get-ACMCertificateDetail |
Select -ExpandProperty RenewalSummary |
Select -ExpandProperty DomainValidationOptions |
Get-Member -MemberType Property
TypeName: Amazon.CertificateManager.Model.DomainValidation
Name MemberType Definition
---- ---------- ----------
DomainName Property string DomainName {get;set;}
ValidationDomain Property string ValidationDomain {get;set;}
ValidationEmails Property System.Collections.Generic.List[string] ValidationEmails {get;set;}
ValidationStatus Property Amazon.CertificateManager.DomainStatus ValidationStatus {get;set;}
Step 2) Make Request
For the sake of example, lets say that we only want to retrieve DomainName and ValidationDomain. We would add two calculated properties for each of these properties, and then just do a regular select for RenewalStatus on the RenewalSummary object:
Get-ACMCertificateList |
Get-ACMCertificateDetail |
Select -ExpandProperty RenewalSummary |
Where-object {$_.RenewalStatus -ne "Success"} |
Select #{N='DomainName';E={$_.DomainValidationOptions.DomainName}}, `
#{N='ValidationDomain';E={$_.DomainValidationOptions.ValidationDomain}}, `
RenewalStatus
Example Output:
DomainName ValidationDomain RenewalStatus
---------- ---------------- -------------
*.subdomain.mydomain.com mydomain.com PENDING_AUTO_RENEWAL
mything.mydomain.com mydomain.com PENDING_AUTO_RENEWAL
You can perform a similar operation for ValidationEmails, I didn't include it in this example because that would have made too many properties to format cleanly on Stack Overflow. If you wanted to unroll the collection and convert it into a string, its calculated property would look something like this:
#{N='ValidationEmails';E={$_.DomainValidationOptions.ValidationEmails -join ','}}
Further Reading
AWS PowerShell Documentation - Get-ACMCertificateDetail
AWS SDK For .NET Documentation - Amazon.CertificateManager.Model.CertificateDetail
- There is an especially helpful note in here about RenewalSummary: "This field exists only when the certificate type is AMAZON_ISSUED."
Additional Note For Readers: I had to update to latest AWS PowerShell to be able to see RenewalSummary. If you can't see this property but expect that you should be able to, try updating your local AWS PowerShell version.
I have a script that creates several jobs and stores two simple values in the jobs.
Start-Job -ScriptBlock {param ([string]$compip) tnc $compip | select RemoteAddress,PingSucceeded -WarningAction SilentlyContinue} -ArgumentList $compip
This works fine. What I would like to know is how can I store the following code into a variable?
Get-Job | Receive-Job | sort RemoteAddress | FT
I have tried this, but it does not work as I thought it would:
$pcs = Get-Job | Receive-Job | sort RemoteAddress | FT
$pcs.RemoteAddress
Am I going at this the wrong way? I would like to store the data from the get-job command above to use the values later in the script. I assumed it would work because the output looks correct:
Command:
Get-Job | Receive-Job | sort RemoteAddress | FT
Output:
RemoteAddress PingSucceeded
------------- -------------
192.168.0.163 True
192.168.0.101 False
192.168.0.2 False
192.168.0.251 True
Problem with Format-cmdlets
The issue here is your use of FT which is an alias for Format-Table. These Format- cmdlets are designed for console/screen output only. There are many things you can do with them to tailor that output but in every case PowerShell needs to massage the data in order to be able to do so. This includes breaking down to the passed objects into groups of different objects...
Microsoft.PowerShell.Commands.Internal.Format.FormatEndData
Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData
Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
Microsoft.PowerShell.Commands.Internal.Format.GroupEndData
Microsoft.PowerShell.Commands.Internal.Format.GroupStartData
The above data types were extract from running this code.
Get-ChildItem c:\temp | Format-Table | Get-Member
So you no longer have the System.IO.FileInfo and System.IO.DirectoryInfo objects that you would normally get from Get-ChildItem
Another large issue comes from Format-cmdlets nature to truncated data, like arrays with a large numbers of elements or long strings, to make as much fit on screen. In the case of arrays, this is due to the preference variable $FormatEnumerationLimit which is commonly defaulted to 4.
Ten Numbers
-----------
{1, 2, 3, 4...}
These, and other, limitations can all be mitigated with cmdlet switches like -AutoSize and -HideTableHeaders, out-string -width, etc. That does not matter however because...
Solution
Good news is the solution is very simple. Stop using them for anything other than console output. Using my earlier example:
Saving results in a variable?: $result = Get-ChildItem C:\temp
Exporting Data: Get-ChildItem C:\temp | Export-CSV $path -NoTypeInformation. Other Export-cmdlets could be preferred here like Export-CLIXml for complex objects when you want to store them for use elsewhere. If you are just looking for something pretty to include in your output then consider ConvertTo-HTML instead.
Extracting individual properties?: Just use Select-Object. $result | Select prop1, prop2. You can also expand your property selection to just get the strings or string array with -ExpandProperty: $result | Select -ExpandProperty prop1
Performing inline calculations with said properties?: Use calculated expression just as you would with the Format-Cmdlets. $result | Select prop1, #{Name="prop2";Expression={$_.prop2 * 3}
Potential Acceptable Use
Some prefer the output for use in emails and for recording statistics. While it is integral to keep data in its more easily used format for later use. However if you really need that data keep in mind that you are not working with the object your originally had anymore.
So if you needed your data in a table format but stored as a string then consider Out-String
$body = Get-ChildItem c:\temp | Format-Table | Out-String
but remember that Format-Table will play with object output in order to get it to display on screen (truncated array properties and long strings). Really.. if you wanted it nice and formatted then you should just use ConvertTo-HTML.
Point is you almost never need to keep the data from Format-Table. There is almost always a better way.