PowerShell cmdlet shows property, but it can't display it through 'select' - powershell

I am trying to execute the following statement.
dir IIS:\Sites| foreach{ get-webapplication -site $_.Name} | select -first 1
This results in
Name Application pool Protocols Physical Path
---- ---------------- --------- -------------
i1 DefaultWebSite http C:\inetpub\hosts\DefaultWebSite\i1
But when I execute the following the result is empty
dir IIS:\Sites| foreach{ get-webapplication -site $_.Name} | select -first 1 name
So I looked into the properties for this object
dir IIS:\Sites| foreach{ get-webapplication -site $_.Name} | select -first 1 | get-member | sort
Name | select Name, MemberType | format-table -auto
Name MemberType
---- ----------
applicationPool NoteProperty
Attributes Property
ChildElements Property
ClearLocalData Method
Collection NoteProperty
ConfigurationPathType NoteProperty
Copy Method
Delete Method
ElementTagName Property
enabledProtocols NoteProperty
Equals Method
GetAttribute Method
GetAttributeValue Method
GetChildElement Method
GetCollection Method
GetHashCode Method
GetMetadata Method
GetParentElement Method
GetType Method
Item ParameterizedProperty
ItemXPath NoteProperty
LoadProperties Method
Location NoteProperty
Methods Property
path NoteProperty
PhysicalPath ScriptProperty
PSPath NoteProperty
Schema Property
SetAttributeValue Method
SetMetadata Method
ToPSObject Method
ToString Method
Update Method
UpdateCollection Method
virtualDirectoryDefaults NoteProperty
So no 'Name' property. How is it that the get-webpplication can show the name property, but we cant select it?

The WebAdministration module defines default format for the concerned type. In this case, the WebApplication that you get is of type Microsoft.IIs.PowerShell.Framework.ConfigurationElement#site#application
If you look at the file iisprovider.format.ps1xml under the module ( usually located at C:\Windows\System32\WindowsPowerShell\v1.0\Modules\WebAdministration), you will see that the format specified for the Name of this type is as below:
...
<TableColumnItem>
<ScriptBlock>
$name = $_.Path.Trim('/')
$name
</ScriptBlock>
</TableColumnItem>
...
Thus the name is actually got from $_.Path.Trim('/'), so you can do the same if you want:
get-webapplication -site "test" | select #{e={$_.Path.Trim('/')};l="Name"}

This works for me:
get-webapplication | forEach { write-host $_.Attributes[0].Value }
Source: https://stackoverflow.com/a/11357353/1158313

Related

Get all the names of the applications in a site

I am trying to write a powershell script which gets the names of each application in a website in IIS in order to change the app pool associated with it. I am able to get the website, but I don't see a clear way to fetch each of the names?
Eg. I want to loop through them all: Api, Services, etc.. and then use
Set-ItemProperty "IIS:\Sites\RootSite\$loopedValue" -Name 'applicationPool' -Value $NewPool
I'm trying this:
Get-WebApplication -Site 'ABC'
Name Application pool Protocols Physical Path
---- ---------------- --------- -------------
Api ABC http C:\Api
Services ABC http C:\Services
Director ABC http C:\Director
ReportingServer ABC http C:\ReportingServer
But there is no way to get the Name from the members of Get-WebApplication.
Get-WebApplication | Get-Member
TypeName: Microsoft.IIs.PowerShell.Framework.ConfigurationElement#site#application
Name MemberType Definition
---- ---------- ----------
ClearLocalData Method void ClearLocalData()
Copy Method void Copy(Microsoft.IIs.PowerShell.Framework.ConfigurationElement target, bool recurse)
Delete Method void Delete()
Equals Method bool Equals(System.Object obj), bool IEquatable[ConfigurationElement].Equals(Microsoft.IIs.PowerShell.Framework.Conf...
GetAttribute Method Microsoft.IIs.PowerShell.Framework.ConfigurationAttribute GetAttribute(string attributeName)
GetAttributeValue Method System.Object GetAttributeValue(string attributeName)
GetChildElement Method Microsoft.IIs.PowerShell.Framework.ConfigurationElement GetChildElement(string elementName), Microsoft.IIs.PowerShel...
GetCollection Method Microsoft.IIs.PowerShell.Framework.ConfigurationElementCollection GetCollection(string collectionName), Microsoft.II...
GetHashCode Method int GetHashCode()
GetMetadata Method System.Object GetMetadata(string metadataType)
GetParentElement Method Microsoft.IIs.PowerShell.Framework.ConfigurationElement GetParentElement()
GetType Method type GetType()
LoadProperties Method void LoadProperties(System.Collections.Generic.Dictionary[string,System.Object] propCollection)
SetAttributeValue Method void SetAttributeValue(string attributeName, System.Object value)
SetMetadata Method void SetMetadata(string metadataType, System.Object value)
ToPSObject Method psobject ToPSObject(Microsoft.IIs.PowerShell.Framework.ConfigurationElement parent)
ToString Method string ToString()
Update Method void Update(Microsoft.IIs.PowerShell.Framework.ConfigurationElement source), bool Update(psobject data)
UpdateCollection Method bool UpdateCollection(psobject[] arr)
applicationPool NoteProperty string applicationPool=ABC
Collection NoteProperty psobject[] Collection=System.Management.Automation.PSObject[]
ConfigurationPathType NoteProperty ConfigurationPathNodeType ConfigurationPathType=Location
enabledProtocols NoteProperty string enabledProtocols=http
ItemXPath NoteProperty string ItemXPath=/system.applicationHost/sites/site[#name='ABC' and #id='1']/application[#path='/API']
Location NoteProperty string Location=
path NoteProperty string path=/ApiDoc
preloadEnabled NoteProperty bool preloadEnabled=False
PSPath NoteProperty string PSPath=MACHINE/WEBROOT/APPHOST
serviceAutoStartEnabled NoteProperty bool serviceAutoStartEnabled=False
serviceAutoStartProvider NoteProperty string serviceAutoStartProvider=
virtualDirectoryDefaults NoteProperty Microsoft.IIs.PowerShell.Framework.ConfigurationElement#application#virtualDirectoryDefaults virtualDirectoryDefault...
Item ParameterizedProperty System.Object Item(string attributeName) {get;set;}
Attributes Property Microsoft.IIs.PowerShell.Framework.ConfigurationAttributeCollection Attributes {get;}
ChildElements Property Microsoft.IIs.PowerShell.Framework.ConfigurationChildElementCollection ChildElements {get;}
ElementTagName Property string ElementTagName {get;}
Methods Property Microsoft.IIs.PowerShell.Framework.ConfigurationMethodCollection Methods {get;}
Schema Property Microsoft.IIs.PowerShell.Framework.ConfigurationElementSchema Schema {get;}
PhysicalPath ScriptProperty System.Object PhysicalPath {get=$pquery = $this.ItemXPath + "/virtualDirectory[#path='/']/#physicalPath"...
I don't really want to parse a string value from the path or PhysicalPath to do this. Is there another way?
An alternative way I came up with was to join the two results from Get-WebSite and Get-WebApplication
(get-website | select-object #{n='Site'; e={$_.Name}},#{n='Location'; e={$_.PhysicalPath}}) + (get-webapplication | select-object #{n='Site'; e= {$_.GetParentElement().Attributes['name'].value + $_.path }},#{n='Location'; e= {$_.PhysicalPath}})
Output:
Site WebType Location
---- ------- --------
MEDIA WebSite c:\mir\data
DATA WebSite d:\data
Tu***.M*.A***o.Sa****x.N***e WebSite C:\WebSite\Tu***.M*.A***o.Sa****x.N***e
Tu***.***********on.*****ime WebSite C:\WebSite\Tu***.***********on.*****ime
Tu***.**.*****.***********ion WebSite C:\WebSite\Tu***.**.*****.***********ion
Tu***.********.**.****App WebSite C:\WEB\Tu***.********.**.****App
Tu***.********.**.****App/api WebApplication C:\Web\Tu***.********.**.****vate
The following will provide the application names for all sites:
(Get-ChildItem -Path 'IIS:\Sites' -Recurse | Where-Object {$_.NodeType -eq 'application'}).Name
The following will return the application names for Default Web Site:
(Get-ChildItem -Path 'IIS:\Sites\Default Web Site' | Where-Object {$_.NodeType -eq 'application'}).Name

why can't I add a member to an ADobject

If I have an object of type Microsoft.ActiveDirectory.Management.ADObject, I can't use Add-Member to add a note property, unless I use -force. If I don't use the force directive, I get an error like:
Add-Member : Cannot add a member with the name "SAMAccountName"
because a member with that name already exists. To overwrite the
member anyway, add the Force parameter to your command.
But, it doesn't already exist. And that happens for any property name. For example:
$domainAccount | Add-Member -NotePropertyName SAMAccountName -NotePropertyValue $account.name
But, this works:
$domainAccount | Add-Member -NotePropertyName SAMAccountName -NotePropertyValue $account.name -force
I can't find documentation that explains this. Can you explain it? And, is there any danger in doing this with the -force directive?
The ADObject class behaves a bit clumsy, in that by simply asking if a property exists, you cause the property to be created if it doesn't.
When Add-Member checks for whether the SAMAccountName property already exists, it incidentally cause it to be created.
Just use the -Force parameter switch.
You can reproduce this behavior yourself:
Import-Module ActiveDirectory
$ADObject = New-Object Microsoft.ActiveDirectory.Management.ADObject
# No SamAccountName property will be listed
$ADObject | Get-Member
Now, try to reference a non-existing property, like "SamAccountName" (the ADObject extends the ADPropertyValueCollection class which is basically a dictionary, so indexing into it's property is totally valid):
$ADObject["SamAccountName"]
# SamAccountName property will now be listed even though we haven't set it
$ADObject | Get-Member
This is not restricted to AD property names, anything goes:
"1 This","2 Is","3 Quite","4 Funky","5 Isn't","6 It?" |ForEach-Object {
[void]$ADObject[$_]
}
$ADObject |Get-Member
Microsoft.ActiveDirectory.Management.ADObject already have SamAccountName property. You don't need to recreate it. Just need define value for it, like this:
$obj = New-Object Microsoft.ActiveDirectory.Management.ADObject
$obj.SamAccountName = 'AccountName'
$obj | Get-Member
Output:
TypeName: Microsoft.ActiveDirectory.Management.ADObject
Name MemberType Definition
---- ---------- ----------
Contains Method bool Contains(string propertyName)
Equals Method bool Equals(System.Object obj)
GetEnumerator Method System.Collections.IDictionaryEnumerator GetEnumerator()
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Item ParameterizedProperty Microsoft.ActiveDirectory.Management.ADPropertyValueCollection Item(string propertyN...
SamAccountName Property Microsoft.ActiveDirectory.Management.ADPropertyValueCollection SamAccountName {get;s...

powershell outputs argument with (#{Name=name}:String)

I'm trying to run the command Get-VMNetworkAdapter on a list of VMs
I'm getting the list with the command:
Get-VM –ComputerName (Get-ClusterNode –Cluster clustername)|select name
and it looks fine, when I'm using
$vmm=Get-VM –ComputerName (Get-ClusterNode –Cluster clustername)|select name
foreach ($item in $vmm)
{Get-VMNetworkAdapter -VMName $item}
it gives me the exception
nvalidArgument: (#{Name=vmname}:String)
like it adds all those symbols..
What is the proper way to lose them?
You need to expand the property. Select doesn't remove the object otherwise:
$vmm = Get-VM –ComputerName (Get-ClusterNode –Cluster clustername) `
| Select-Object -ExpandProperty name
To explain what -ExpandProperty does:
First of all, the drawback of -ExpandProperty is that you can only do it to one property at a time.
Select-Object normally wraps the results in another object so that properties remain properties. If you say $x = Get-ChildItem C:\Windows | Select-Object Name, then you get an object array with one property: Name.
PS C:\> $x = Get-ChildItem C:\Windows | Select-Object Name
PS C:\> $x
Name
----
45235788142C44BE8A4DDDE9A84492E5.TMP
8A809006C25A4A3A9DAB94659BCDB107.TMP
.
.
.
PS C:\> $x[0].Name
45235788142C44BE8A4DDDE9A84492E5.TMP
PS C:\> $x[0].GetType().FullName
System.Management.Automation.PSCustomObject
Notice the header? Name is a property of the object.
Also, the base object with it's type is still kind of there:
PS C:\> $x | Get-Member
TypeName: Selected.System.IO.DirectoryInfo
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Name NoteProperty string Name=45235788142C44BE8A4DDDE9A84492E5.TMP
TypeName: Selected.System.IO.FileInfo
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Name NoteProperty string Name=bfsvc.exe
Normally, that's all great. Especially because we normally want multiple properties of the object.
Sometimes, however, not what we want. Sometimes, we want an array that's the same type as the property we selected. When we use it later we want just that property and nothing else and we want it to be the exact same type as the property and nothing else.
PS C:\> $y = Get-ChildItem C:\Windows | Select-Object -ExpandProperty Name
PS C:\> $y
45235788142C44BE8A4DDDE9A84492E5.TMP
8A809006C25A4A3A9DAB94659BCDB107.TMP
.
.
.
PS C:\> $y[0].Name
PS C:\> $y[0]
45235788142C44BE8A4DDDE9A84492E5.TMP
PS C:\> $y.GetType().FullName
System.Object[]
PS C:\> $y[0].GetType().FullName
System.String
Notice there's no header, and any calls to a Name property fail; there is no Name property anymore.
And, there's nothing left over from the original object:
PS C:\> $y | Get-Member
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
.
.
.
.
Basically, here it's the equivalent of doing this:
$z = Get-ChildItem C:\Windows | ForEach-Object { $_.Name }
Which I think is how you had to do it in PowerShell v1.0 or v2.0... it's been too many years since I've used that to remember right.

Using a Powershell noteproperty as a text string in a variable

I've used Invoke-Restmethod to download some data, which Powershell stores in a PSCustomObject, in a property called data.
I need to use the value of one of the items in the returned data as a variable for another command. I have managed to select-object -expand my way down to the following output from Get-Member:
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
id NoteProperty System.Int32 id=999
What I need to do is grab the value of the ID noteproperty - 999 - and pass that as part of a string to a new variable, eg:
$newVar = "sometext" + 999 + "moretext"
No amount of select-string or out-string etc is helping. Scripting is not exactly my strong point so I'm not sure I'm even articulating what I want properly - apologies if this is the case!
Any assistance much appreciated
I'm not sure exactly what your code and looks like, so I created the following static approximation from the description:
$data = New-Object PSCustomObject
$data | Add-Member -Type NoteProperty -Name Id -Value 999
$restResponse = New-Object PSCustomObject
$restResponse | Add-Member -Type NoteProperty -Name data -Value $data
Please clarify if this is not a match. You can get the Id value as follows
$restResponse.data.Id
Assign it to another variable
$newVar = "sometext" + $restResponse.data.Id + "moretext"
$newVar
And if your REST response is a collection of data objects, iterate through them
$restResponse.data | Foreach-Object { "sometext" + $_.Id + "moretext" }
I would go for for using $output | select *,#{n='test';e={[string]$_.test}} -exclude properties test
if the exclude is not active it will complain about it already exists. Mostly I use the select expression to manipulate data realtime instead of psCustomObject for such simple task

Printing object properties in Powershell

When working in the interactive console if I define a new object and assign some property values to it like this:
$obj = New-Object System.String
$obj | Add-Member NoteProperty SomeProperty "Test"
Then when I type the name of my variable into the interactive window Powershell gives me a summary of the object properties and values:
PS C:\demo> $obj
SomeProperty
------------
Test
I basically want to do just this but from within a function in a script. The function creates an object and sets some property values and I want it to print out a summary of the object values to the Powershell window before returning. I tried using Write-Host within the function:
Write-Host $obj
But this just output the type of the object not the summary:
System.Object
How can I have my function output a summary of the object's property values to the Powershell window?
Try this:
Write-Host ($obj | Format-Table | Out-String)
or
Write-Host ($obj | Format-List | Out-String)
My solution to this problem was to use the $() sub-expression block.
Add-Type -Language CSharp #"
public class Thing{
public string Name;
}
"#;
$x = New-Object Thing
$x.Name = "Bill"
Write-Output "My name is $($x.Name)"
Write-Output "This won't work right: $x.Name"
Gives:
My name is Bill
This won't work right: Thing.Name
To print out object's properties and values in Powershell. Below examples work well for me.
$pool = Get-Item "IIS:\AppPools.NET v4.5"
$pool | Get-Member
TypeName: Microsoft.IIs.PowerShell.Framework.ConfigurationElement#system.applicationHost/applicationPools#add
Name MemberType Definition
---- ---------- ----------
Recycle CodeMethod void Recycle()
Start CodeMethod void Start()
Stop CodeMethod void Stop()
applicationPoolSid CodeProperty Microsoft.IIs.PowerShell.Framework.CodeProperty
state CodeProperty Microsoft.IIs.PowerShell.Framework.CodeProperty
ClearLocalData Method void ClearLocalData()
Copy Method void Copy(Microsoft.IIs.PowerShell.Framework.ConfigurationElement ...
Delete Method void Delete()
...
$pool | Select-Object -Property * # You can omit -Property
name : .NET v4.5
queueLength : 1000
autoStart : True
enable32BitAppOnWin64 : False
managedRuntimeVersion : v4.0
managedRuntimeLoader : webengine4.dll
enableConfigurationOverride : True
managedPipelineMode : Integrated
CLRConfigFile :
passAnonymousToken : True
startMode : OnDemand
state : Started
applicationPoolSid : S-1-5-82-271721585-897601226-2024613209-625570482-296978595
processModel : Microsoft.IIs.PowerShell.Framework.ConfigurationElement
...
Tip #1
Never use Write-Host.
Tip #12
The correct way to output information from a PowerShell cmdlet or function is to create an object that contains your data, and then to write that object to the pipeline by using Write-Output.
-Don Jones: PowerShell Master
Ideally your script would create your objects ($obj = New-Object -TypeName psobject -Property #{'SomeProperty'='Test'}) then just do a Write-Output $objects. You would pipe the output to Format-Table.
PS C:\> Run-MyScript.ps1 | Format-Table
They should really call PowerShell PowerObjectandPipingShell.
Some general notes.
$obj | Select-Object ⊆ $obj | Select-Object -Property *
The latter will show all non-intrinsic, non-compiler-generated properties. The former does not appear to (always) show all Property types (in my tests, it does appear to show the CodeProperty MemberType consistently though -- no guarantees here).
Some switches to be aware of for Get-Member
Get-Member does not get static members by default. You also cannot (directly) get them along with the non-static members. That is, using the switch causes only static members to be returned:
PS Y:\Power> $obj | Get-Member -Static
TypeName: System.IsFire.TurnUpProtocol
Name MemberType Definition
---- ---------- ----------
Equals Method static bool Equals(System.Object objA, System.Object objB)
...
Use the -Force.
The Get-Member command uses the Force parameter to add the intrinsic members and compiler-generated members of the objects to the display. Get-Member gets these members, but it hides them by default.
PS Y:\Power> $obj | Get-Member -Static
TypeName: System.IsFire.TurnUpProtocol
Name MemberType Definition
---- ---------- ----------
...
pstypenames CodeProperty System.Collections.ObjectModel.Collection...
psadapted MemberSet psadapted {AccessRightType, AccessRuleType,...
...
Use ConvertTo-Json for depth and readable "serialization"
I do not necessary recommend saving objects using JSON (use Export-Clixml instead).
However, you can get a more or less readable output from ConvertTo-Json, which also allows you to specify depth.
Note that not specifying Depth implies -Depth 2
PS Y:\Power> ConvertTo-Json $obj -Depth 1
{
"AllowSystemOverload": true,
"AllowLifeToGetInTheWay": false,
"CantAnyMore": true,
"LastResortOnly": true,
...
And if you aren't planning to read it you can -Compress it (i.e. strip whitespace)
PS Y:\Power> ConvertTo-Json $obj -Depth 420 -Compress
Use -InputObject if you can (and are willing)
99.9% of the time when using PowerShell: either the performance won't matter, or you don't care about the performance. However, it should be noted that avoiding the pipe when you don't need it can save some overhead and add some speed (piping, in general, is not super-efficient).
That is, if you all you have is a single $obj handy for printing (and aren't too lazy like me sometimes to type out -InputObject):
# select is aliased (hardcoded) to Select-Object
PS Y:\Power> select -Property * -InputObject $obj
# gm is aliased (hardcoded) to Get-Member
PS Y:\Power> gm -Force -InputObject $obj
Caveat for Get-Member -InputObject:
If $obj is a collection (e.g. System.Object[]), You end up getting information about the collection object itself:
PS Y:\Power> gm -InputObject $obj,$obj2
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
...
If you want to Get-Member for each TypeName in the collection (N.B. for each TypeName, not for each object--a collection of N objects with all the same TypeName will only print 1 table for that TypeName, not N tables for each object)......just stick with piping it in directly.
The below worked really good for me. I patched together all the above answers plus read about displaying object properties in the following link and came up with the below
short read about printing objects
add the following text to a file named print_object.ps1:
$date = New-Object System.DateTime
Write-Output $date | Get-Member
Write-Output $date | Select-Object -Property *
open powershell command prompt, go to the directory where that file exists and type the following:
powershell -ExecutionPolicy ByPass -File is_port_in_use.ps1 -Elevated
Just substitute 'System.DateTime' with whatever object you wanted to print. If the object is null, nothing will print out.
# Json to object
$obj = $obj | ConvertFrom-Json
Write-host $obj.PropertyName