Powershell: How to use select-object to get a dynamic set of properties?

10,110

Solution 1

I would suggest taking in the paramters as a normal string[] (Array) parameter, and use it to create an array of hashtables (custom expressions for Select-Object). Then supply the hashtable with Select-Object. Ex:

param (
    [String[]]$Fields
)

#Create property-array for Select-Object
$props = @()

#Add mandatory displayname property
$props += @{n="DisplayName";e=([Scriptblock]::Create("`$_.DisplayName"))}

#Add user-defined fields
foreach ($field in $Fields) { 
    $props += @{n=$field;e=([Scriptblock]::Create("`$_.Item($field)"))}
}

#Later in code
$web.Lists | foreach{
    $lib = $_
    if($lib.BaseType -eq [Microsoft.SharePoint.SPBaseType]::DocumentLibrary  `
    -and $lib.BaseTemplate -eq [Microsoft.SharePoint.SPListTemplateType]::DocumentLibrary)
    {
        $lib.Items | Select-Object -Property $props
    }

 }
#Usage: .\psextractor -Fields "Type", "Name", "User", "Desc"
#This will list all fields specified after '-Fields'

Solution 2

You can try like this:

param([object[]]$fields)

$fields += "DisplayName"

 $web.Lists | foreach{
    $lib = $_
    if($lib.BaseType -eq [Microsoft.SharePoint.SPBaseType]::DocumentLibrary 
           -and $lib.BaseTemplate -eq [Microsoft.SharePoint.SPListTemplateType]::DocumentLibrary){
        $lib.Items |  Select-Object -property $fields
    }

 }

call your function like this:

myfunction.ps1 -fields Type,name,User,Description
Share:
10,110

Related videos on Youtube

Realistic
Author by

Realistic

Updated on June 25, 2022

Comments

  • Realistic
    Realistic almost 2 years

    I am using powershell in conjunction with sharepoint 07 to list some stuff out. I am trying to allow a (power) user to specify which Fields they want to display.
    For example, I could run my code as follows:
    .\psextractor -fields "Type|name|User Desc
    After doing this I would get a list of files displaying the fields listed above. Currently I am using the Select-Object identifier and I was wondering if this was possible. If not, is there a way to do this without using the create-object cmdlet?
    My code:

    #$Args
    if($Args[0] -eq "-fields" -and $Args.Count -ge 2){
        $flds = $Args[1].split("|")
    }
    
    #Later in code
     $web.Lists | foreach{
        $lib = $_
        if($lib.BaseType -eq [Microsoft.SharePoint.SPBaseType]::DocumentLibrary 
               -and $lib.BaseTemplate -eq [Microsoft.SharePoint.SPListTemplateType]::DocumentLibrary){
            $lib.Items |  Select-Object DisplayName,
                      @{n=$flds[0];e={$_.Item($flds[0])}} ,
                      @{n=$flds[1];e={$_.Item($flds[1])}}
                      #, etc, etc
    
        }
    
     }
    

    EDIT: I used Graimer's solution below with a few tweaks

    SOLUTION:

    param([object[]]$flds)
    $props=@() #globally declared since some of this is done in functions later
    
    $mflds = $("Author","Created","Modified","Modified By") #mandatory fields
    $mflds | foreach{
        if($flds -notcontains $_){
            $flds += $_
        }
    }
    #had to use regular for loop because the $_ identifier was conflicting
    for ($i =0; $i -lt $flds.Count; $i++) { 
        $props += @{n=$flds[$i];e=([Scriptblock]::Create("`$_[`$flds[$i]]"))}
    }
    #other mandatory custom fields
        #the create method could have been used here
    $props += @{n="FileName";e={"$($_.Item('Name'))"}}
    $props += @{n="Url";e={"$wburl/$($_.Url)"}}
    
    #Later in code
     $web.Lists | foreach{
        $lib = $_
        if($lib.BaseType -eq [Microsoft.SharePoint.SPBaseType]::DocumentLibrary 
               -and $lib.BaseTemplate -eq [Microsoft.SharePoint.SPListTemplateType]::DocumentLibrary){
            $lib.Items |  Select-Object -property $props
    
        }
    
     }
    
  • Realistic
    Realistic about 11 years
    This does not work because the properties are stored within the object that is being selected. That is why I had to use $_.Item("Field I need"). Similarly they can be accessed like so: $itm = $_; $itm["Field I need"]. I'm not sure how SP did this but its a pain :(
  • Frode F.
    Frode F. about 11 years
    Btw, if people are going to downvote my answers, I would very much appreciate a comment specifying what I should improve. This is a community, we're supposed to help each other to get better.
  • Realistic
    Realistic about 11 years
    I hope I didn't accidentally down vote you because your post was definitely helpful. However, as I stated on the other answer, you cannot get these properties in this manner. The only way they can be accessed is via a method or by using hashing ie: @{$_["my fields"]} or @{$_get("My Field")}. The syntax is pseudo but I hope you get the point. If you have any suggestions for this please share.
  • Realistic
    Realistic about 11 years
    I have figured it out! the $_ was conflicting but besides that this was perfect. See the edit to my post which includes a full solution.
  • Frode F.
    Frode F. about 11 years
    it's good it worked out :) however I can't see your problem. my foreachloop did not use a $_ that would conflict anywhere. My references to it was escaped with a backtick(in the create scriptblock part). As long as the Item object you want to extract from supports a Item(string) method it should work. If it is a normal hashtable, a change to ..=([Scriptblock]::Create("'$_[($field)]")) should be enough (where ' infront of $_ is a backtick). :-)