As you saw in the first post in this series, getting a PowerShell provider up and running is pretty easy. Next we are going to add some basic GetChildItems() support and provide a nice experience to your users.

A good starting point for this article is the GetStackOverflowTags tag in the GitHub repo for this project. I have added a basic StackOverflow API at this point that allows me to get a list of tags from StackOverflow ordered by the most popular tags.

After adding the API, I simply updated the GetChildItems() call to consume the API and return the object to the PowerShell window.

protected override void GetChildItems(string path, bool recurse)
{
    var stackOverflow = new StackOverflowAPI.StackOverflow();
    var tags = stackOverflow.GetTags().Result;

    foreach (var tag in tags)
    {
        WriteItemObject(tag, tag.name,true);
    }
}

Now, anytime you call dir, you get output that looks like this:

PSPath            : PowerShellProvider\MyPowerShellProvider::java
PSParentPath      : 
PSChildName       : java
PSDrive           : MyDrive
PSProvider        : PowerShellProvider\MyPowerShellProvider
PSIsContainer     : True
has_synonyms      : True
is_moderator_only : False
is_required       : False
count             : 669099
name              : java

Not very user friendly. You could use various PowerShell constructs to format the output like you want, for example, I could do dir | Format-Table -Property Name,Count to get the output:

name                                                                  count
----                                                                  -----
java                                                                  669099
c#                                                                    663666
javascript                                                            647161
php                                                                   603881
...

Instead of forcing the user to type that every time, we can modify our project to use a PowerShell manifest and a custom formatting file to get our desired output on a dir command. Create a new file called MyPowerShellProvider.psd1 and set its build action to Content and CopyToOutputDirectory to Copy if newer.

Copy the contents of the sample manifest file and update the following lines:

# Script module or binary module file associated with this manifest
RootModule = 'PowerShellProvider.dll'

# Version number of this module.
ModuleVersion = '1.0'

# ID used to uniquely identify this module
GUID = 'AE0DA9B1-93DF-4959-9C97-BAA45D5F8EE0'

# Author of this module
Author = 'John Koerner'

# Company or vendor of this module
CompanyName = ''

# Copyright statement for this module
Copyright = 'See the license file for this repo'

Update your InstallProvider.ps1 file to point to the new psd1 file:

Import-Module .\MyPowerShellProvider.psd1

At this point, your provider should still work as before, but now it is loading the information based on the .psd1 file. Next we will create a custom formatting file. I am simply going to modify the table output to use the Name and Count fields. Create a new file named MyViewDefinition.ps1xml and set the Copy to Output Directory to Copy if newer. For the contents of this file, use the following:

<Configuration>
  <ViewDefinitions>
    <View>
      <Name>MyView</Name>
      <ViewSelectedBy>
        <TypeName>StackOverflowAPI.Tag</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <TableHeaders>
          <TableColumnHeader>
            <Label>Name</Label>
            <Width>25</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Count</Label>
            <Width>10</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>Name</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Count</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>

Some of the important bits here are that we set the TypeName node in the ViewSelectedBy node to our type that we are using. This can give us a lot of flexibility if we want different formatting for different types of data. We then set table headers to our desired header information and then one TableColumnItem for each header we defined, telling it from which property it can obtain the value.

Finally we can update the .psd1 file to leverage this formatting, by updating the FormatsToProcess line to include our ps1xml file.

FormatsToProcess = @("MyViewDefinition.ps1xml")

Now when you run dir on MyDrive: you will get the following output:

Name                      Count
----                      -----
java                      671397
c#                        665365
javascript                649489
php                       606076
android                   534244
jquery                    503075
python                    318616
...

At this point you have a drive that can show a single level of depth and the dir output doesn't look half bad. In the next article, we will really dig into navigation and work on navigating in and out of folders and have valid dir contents at every depth.