Does Get-WebApplication returns invalid objects? - powershell

Why do I don't get valid names, if I use Get-WebApplication in PowerShell like this:
Get-WebApplication | ForEach-Object { write-host $_.Name }
In the result set, the name properties are empty. Why?
Instead Get-WebApplication does return a structure like:
PS> Get-WebApplication
Name Application pool Protocols Physical Path
---- ---------------- --------- -------------
test default http C:\....

Assuming Get-WebApplication is https://technet.microsoft.com/en-us/library/ee790554.aspx.
Name column in the output from Get-WebApplication seems to behave a little like a calculated property. I was unable to find out exactly what the formula is behind it but by running
Get-WebApplication | select -ExpandProperty Path | select #{ n="Name";e={ $_.TrimStart('/') } }
you will get a similar looking result as to what you appear to be trying to extract.
This command selects and simplifies the Path property (essentially turns it into a string), then creates from it a calculated property that has the correct title and value.

Related

PowerShell custom output #{n=;e=}

I'm not very clear on how the #{n=;e=} construct works in PowerShell.
Does this type of thing have a name that I can find examples from?
For example, I find examples like this that works great:
gwmi win32_logicaldisk | Format-Table DeviceId, VolumeName, #{n="Size(GB)";e={[math]::Round($_.Size/1GB,2)}},#{n="Free(GB)";e={[math]::Round($_.FreeSpace/1GB,2)}}
When I try to do something like that, I can never get it to work. This works fine:
Get-Command -Module Microsoft.Powershell.Utility | Where CommandType -eq Function | Select Name,Version,CommandType
So I thought I would try and add the definition of that function to a new column using cat function:\$_.Name
Get-Command -Module Microsoft.Powershell.Utility | Where CommandType -eq Function | Select Name,Version,CommandType,#{n="Contents"; e={cat function:\$_.Name}}
But I just get an empty Contents column :(
Can someone give me some pointers on how the #{n=;e=} construct works?
Also, what do the n and e stand for?
#{n='';e={}} syntax is called a calculated property. n stands for Name and e stands for expression. You can even specify Name instead of n and Expression instead of e.
Calculated properties allow you to create new properties or change existing ones. This is done by passing a special hashtable to the Property parameter rather than a static property name. This is a useful feature where you create new properties using custom expression in a script block and use existing properties.
Not for only Select-Object this work for also Format-Table, Format-List cmdlets. These don't work outside this cmdlets.
Calculated properties are a quick way to manipulate command output to return just about anything you like. These save your time and reduce code length.
Sidenote: The last code in your question dosent work because you need to join two path using Join-Path. Calculated properties are innocent here. Even you can join path like this: cat "Function:\$($_.Name)" as #MathiasR.Jessen pointed.
#{} is a hashtable. {} is a scriptblock inside the hashtable set equal to e. The hashtable is used in a custom way for select-object.
$scriptblock = { $_ }
$hashtable = #{ name = 'number'
expression = $scriptblock
}
1..3 | select-object -property $hashtable
number
------
1
2
3

Return full value of a property

I'm trying to get the Program IDs of DCOM applications but when returning the value of the property, it doesn't give the full contents.
$a = Get-ChildItem 'registry::HKEY_CLASSES_ROOT\WOW6432Node\CLSID\' -Recurse | Where-Object Name -match 'ProgID'
This returns all applications that contain a ProgID
Hive: HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{000C1090-0000-0000-C000-000000000046}
Name Property
---- --------
ProgId (default) : WindowsInstaller.Installer
When trying to get the property value in the example, "WindowsInstaller.Installer"
via $a.Property
returns
(default)
How do I return the full property contents?
What Get-ChildItem returns for registry locations are Microsoft.Win32.RegistryKey instances representing registry keys.
To get the data for the unnamed default value of each such key - which contains the ProgID of interest - you can use the .GetValue() method with the empty string ('').
Note that PowerShell represents the unnamed default value differently, as '(default)', as shown in your question.
Get-ChildItem registry::HKEY_CLASSES_ROOT\WOW6432Node\CLSID -Recurse |
Where-Object Name -match ProgID |
ForEach GetValue ''
As an aside: the Name property of registry [Microsoft.Win32.RegistryKey] instances contains the full key path, so a better way to limit matching to just a key's name is to use
Where-Object Name -match '\\ProgID$ in your case.

Passing subset of objects down pipeline, based on count of properties?

I need to script up some things in PowerCLI (VMWare's bolt on to PowerShell). Basically we have a server cluster with three hosts. Each host has multiple virtual switches. Each virtual switch has multiple vlans ('port groups' in VMWare speak). I need to audit the fact that the same port groups exist on each host (so things keep working if the VM is moved).
Step 1 to achieving this is would be to know that the port group name exists on each of the three host machines.
I'm falling over with how to filter some objects out of all the ones returned by a cmdlet, based on number of results returned from a property of those objects. I then need to perform further operations with original object type that passes the filter test to go on down the pipeline.
To give some specifics, this an example showing 'Some PortGroup Name' and the three hosts it exists on (and as a bonus, the vSwitch):
Get-VirtualPortGroup -Name 'Some PortGroup Name' |
Select-Object Name, VMHostID, VirtualSwitchId
produces the output
Name VMHostId VirtualSwitchId
---- -------- ---------------
Some PortGroup Name HostSystem-host-29459 key-vim.host.VirtualSwitch-vSwitch6
Some PortGroup Name HostSystem-host-29463 key-vim.host.VirtualSwitch-vSwitch6
Some PortGroup Name HostSystem-host-29471 key-vim.host.VirtualSwitch-vSwitch6
Instead of 3, I'm starting with the 1849 port group names that are being returned by Get-VirtualPortGroup. I need a pipeline to whittle the number of VirtualPortGroup objects down to a collection consisting of only those objects where a count of the 'VMHostId' property is less than 3, and pass the remaining VirtualPortGroup objects down the pipeline for further processing.
This seems simple enough to do. I'm still failing though.
The following almost works. Piping it to measure shows a count of 229, instead of the original 1849 (so it's definitely filtered a lot out, and is possibly correctly returning the subset I'm after...?). The problem is, the object type is now a 'Group' or something at this point in the pipeline, and doesn't have all the properties and methods of the original Get-VirtualPortGroup objects.
Get-VirtualPortGroup |
Group-Object -Property Name |
Where-Object $_.Count -lt 3
Bolting a | Select-Object -ExpandProperty Group to the end of the above seemed promising, except it then seems to return the entire collection of Get-VirtualPortGroup objects as though I had done no filtering in there at all....
Am I doing something fundamentally wrong?
How can I filter out objects based on the count of the number of results returned by a specific property of an object, but still pass the original object type down the pipe?
Your approach is correct, but you got the Where-Object syntax wrong. The abbreviated syntax is:
Where-Object <property> <op> <value>
without the current object variable ($_). In your case that would be:
Where-Object Count -lt 3
Otherwise you must use scriptblock notation:
Where-Object { $_.Count -lt 3 }
This should do what you want:
Get-VirtualPortGroup |
Group-Object -Property Name |
Where-Object { $_.Count -lt 3 } |
Select-Object -Expand Group

Using Where-Object with an object in PowerShell

I can't seem to get my brain around something and I am hoping someone can help
I have an array of objects called $SnapVMsAll that looks like this:
VMName Name SnapshotType CreationTime ParentSnapshotName
------ ---- ---------- ------------ ------------------
SHARED-server.host.com SHARED-server.host.com - (02/10/2017 - 13:02:44) Standard 02/10/2017 13:05:58
I need to display all the records in this array of objects that have string "Veeam" in the name column, but I think I am having problems isolating a specific attribute of the object to compare.
My attempts have been as follows:
echo $SnapVMsAll | Where-Object (Foreach-Object -MemberName name) -Like "Veeam Replica"
This returned the error:
Where-Object : Cannot validate argument on parameter 'Property'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
I have also tried
echo $SnapVMsAll | Where-Object $SnapVMsAll.name -Like "Veeam Replica"
But again I get the same error.
$SnapVMsAll does not exist inside the pipeline, it is the object you pass to the pipeline. Within a pipeline, objects can be accessed using the automatic variable $_.
Also note that -Like is usually used with wildcards to match a string. If the name is Veeam Replica you should use -eq, if the name contains Veeam Replica, you should change to -Like "*Veeam Replica*"
So changing your code to the following should work:
$SnapVMsAll | Where-Object { $_.name -Like "*Veeam Replica*" }

How to remove curly brackets from the PowerShell output

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.