Meteorhead
Meteorhead

Reputation: 516

Select-Object -ExpandProperty vs. Get-ItemPropertyValue

Most likely there's something fundamental I don't understand about PowerShell. I really don't like when writing even medium sized pipes, where grabbing a property breaks the workflow by having to put parens around the statement up to that point, for eg.

(Get-ChildItem ~\.gitconfig).Length

This is tedious. Because Length looks very much like a property, one would think

Get-ChildItem ~\.gitconfig | Get-ItemPropertyValue -Name Length

would work. However, it does not. Taking a look at the interface of the System.IO.FileSystemInfo object returned by the File System PSDrive provider, one sees that it doesn't have a Length property. It does have a FullName property though, hence

Get-ChildItem ~\.gitconfig | Get-ItemPropertyValue -Name FullName

works as expected. To retrieve the size (Length) of a file using the pipe, one has to use Select-Object with the -ExpandProperty like

Get-ChildItem ~\.gitconfig | Select-Object -ExpandProperty Length

How does one know up front whether placing a . after an object and iterating through the results of tab completion, if the entry is an object or a property? It's very annoying that even common operations are confusing as hell, given for instance that reading environmental variables goes by

Get-Item -Path Env:\USERNAME

returns

Name                           Value
----                           -----
USERNAME                       mnagy

If it's an item, Get-ItemProperty and Get-ItemPropertyValue must play a role here. Because of the Name:Value structure of the result, newcomers might be intrigued to obtain the actual value saying

Get-Item -Path Env:\USERNAME | Get-ItemPropertyValue

or actually reading how Get-ItemPropertyValue should be used modify the query to

Get-ItemPropertyValue -Path Env:\ -Name USERNAME

which in fact results in

Get-ItemPropertyValue : Cannot use interface. The IPropertyCmdletProvider interface is not supported by this provider.
At line:1 char:1
+ Get-ItemPropertyValue -Path Env:\ -Name USERNAME
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotImplemented: (:) [Get-ItemPropertyValue], PSNotSupportedException
+ FullyQualifiedErrorId : NotSupported,Microsoft.PowerShell.Commands.GetItemPropertyValueCommand

This entire construction seems utterly inconsistent to me and most vexing, but hopefully not by design, but because I look at it from the wrong angle.

Upvotes: 0

Views: 1755

Answers (1)

tukan
tukan

Reputation: 17347

To your first note: Length, for .hg directoy, worked form me just fine (giving you the number of files within):

Ps C:\>    (Get-ChildItem .hg).Length
18

I tend to use get-member to check what is supported and what is not.

If I check it for my directory reports:

(Get-ChildItem reports) | gm


   TypeName: System.IO.FileInfo

Name                      MemberType     Definition
----                      ----------     ----------
LinkType                  CodeProperty   System.String LinkType{get=GetLinkType;}
Mode                      CodeProperty   System.String Mode{get=Mode;}
Target                    CodeProperty   System.Collections.Generic.IEnumerable`1[[System.String, mscorlib, Version=...
AppendText                Method         System.IO.StreamWriter AppendText()
CopyTo                    Method         System.IO.FileInfo CopyTo(string destFileName), System.IO.FileInfo CopyTo(s...
Create                    Method         System.IO.FileStream Create()
CreateObjRef              Method         System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
CreateText                Method         System.IO.StreamWriter CreateText()
Decrypt                   Method         void Decrypt()
Delete                    Method         void Delete()
Encrypt                   Method         void Encrypt()
Equals                    Method         bool Equals(System.Object obj)
GetAccessControl          Method         System.Security.AccessControl.FileSecurity GetAccessControl(), System.Secur...
GetHashCode               Method         int GetHashCode()
GetLifetimeService        Method         System.Object GetLifetimeService()
GetObjectData             Method         void GetObjectData(System.Runtime.Serialization.SerializationInfo info, Sys...
GetType                   Method         type GetType()
InitializeLifetimeService Method         System.Object InitializeLifetimeService()
MoveTo                    Method         void MoveTo(string destFileName)
Open                      Method         System.IO.FileStream Open(System.IO.FileMode mode), System.IO.FileStream Op...
OpenRead                  Method         System.IO.FileStream OpenRead()
OpenText                  Method         System.IO.StreamReader OpenText()
OpenWrite                 Method         System.IO.FileStream OpenWrite()
Refresh                   Method         void Refresh()
Replace                   Method         System.IO.FileInfo Replace(string destinationFileName, string destinationBa...
SetAccessControl          Method         void SetAccessControl(System.Security.AccessControl.FileSecurity fileSecurity)
ToString                  Method         string ToString()
PSChildName               NoteProperty   string PSChildName=jv_libgdbs_tests-20180822-Test.xml
PSDrive                   NoteProperty   PSDriveInfo PSDrive=C
PSIsContainer             NoteProperty   bool PSIsContainer=False
PSParentPath              NoteProperty   string PSParentPath=Microsoft.PowerShell.Core\FileSystem::C:\prg_sdk\stx8-j...
PSPath                    NoteProperty   string PSPath=Microsoft.PowerShell.Core\FileSystem::C:\prg_sdk\stx8-jv_swin...
PSProvider                NoteProperty   ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem
Attributes                Property       System.IO.FileAttributes Attributes {get;set;}
CreationTime              Property       datetime CreationTime {get;set;}
CreationTimeUtc           Property       datetime CreationTimeUtc {get;set;}
Directory                 Property       System.IO.DirectoryInfo Directory {get;}
DirectoryName             Property       string DirectoryName {get;}
Exists                    Property       bool Exists {get;}
Extension                 Property       string Extension {get;}
FullName                  Property       string FullName {get;}
IsReadOnly                Property       bool IsReadOnly {get;set;}
LastAccessTime            Property       datetime LastAccessTime {get;set;}
LastAccessTimeUtc         Property       datetime LastAccessTimeUtc {get;set;}
LastWriteTime             Property       datetime LastWriteTime {get;set;}
LastWriteTimeUtc          Property       datetime LastWriteTimeUtc {get;set;}
Length                    Property       long Length {get;}
Name                      Property       string Name {get;}
BaseName                  ScriptProperty System.Object BaseName {get=if ($this.Extension.Length -gt 0){$this.Name.Re...
VersionInfo               ScriptProperty System.Object VersionInfo {get=[System.Diagnostics.FileVersionInfo]::GetVer...

How does one know up front whether placing a . after an object and iterating through the results of tab completion, if the entry is an object or a property?

You check it with with Get-Member.

For the Get-Item -Path Env:\USERNAME you can again check:

PS C:\> Get-Item -Path Env:\USERNAME | gm


   TypeName: System.Collections.DictionaryEntry

Name          MemberType    Definition
----          ----------    ----------
Name          AliasProperty Name = Key
Equals        Method        bool Equals(System.Object obj)
GetHashCode   Method        int GetHashCode()
GetType       Method        type GetType()
ToString      Method        string ToString()
PSDrive       NoteProperty  PSDriveInfo PSDrive=Env
PSIsContainer NoteProperty  bool PSIsContainer=False
PSPath        NoteProperty  string PSPath=Microsoft.PowerShell.Core\Environment::USERNAME
PSProvider    NoteProperty  ProviderInfo PSProvider=Microsoft.PowerShell.Core\Environment
Key           Property      System.Object Key {get;set;}
Value         Property      System.Object Value {get;set;}

Now check the USERNAME (you see the key you are asking and its value):

PS C:\> (Get-Item -Path Env:\USERNAME).key
USERNAME
PS C:\> (Get-Item -Path Env:\USERNAME).value # my login
gurun 

Upvotes: 1

Related Questions