Writing an item provider
This topic describes how to implement the methods of a Windows PowerShell provider that access and manipulate items in the data store. To be able to access items, a provider must derive from the ItemCmdletProvider class.
The provider in the examples in this topic uses an Access database as its data store. There are several helper methods and classes that are used to interact with the database. For the complete sample that includes the helper methods, see AccessDBProviderSample03
For more information about Windows PowerShell providers, see Windows PowerShell Provider Overview.
The ItemCmdletProvider class exposes several methods that can be used to access and manipulate the items in a data store. For a complete list of these methods, see ItemCmdletProvider Methods. In this example, we will implement four of these methods. GetItem gets an item at a specified path. SetItem sets the value of the specified item. ItemExists checks whether an item exists at the specified path. IsValidPath checks a path to see if it maps to a location in the data store.
Note |
|---|
This topic builds on the information in Windows PowerShell Provider QuickStart. This topic does not cover the basics of how to set up a provider project, or how to implement the methods inherited from the DriveCmdletProvider class that create and remove drives. |
Declare the provider to derive from the ItemCmdletProvider class, and decorate it with the CmdletProviderAttribute.
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : ItemCmdletProvider
{
}
The GetItem is called by the PowerShell engine when a user calls the T:Microsoft.PowerShell.Commands.Get-Item cmdlet on your provider. The method returns the item at the specified path. In the Access database example, the method checks whether the item is the drive itself, a table in the database, or a row in the database. The method sends the item to the PowerShell engine by calling the WriteItemObject method.
protected override void GetItem(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out rowNumber);
if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}
}
The SetItem method is called by the PowerShell engine calls when a user calls the T:Microsoft.PowerShell.Commands.Set-Item cmdlet. It sets the value of the item at the specified path.
In the Access database example, it makes sense to set the value of an item only if that item is a row, so the method throws NotSupportedException when the item is not a row.
protected override void SetItem(string path, object values)
{
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out rowNumber);
if (type != PathType.Row)
{
WriteError(new ErrorRecord(new NotSupportedException(
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
}
// Get in-memory representation of table
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);
if (rowNumber >= table.Rows.Count)
{
// The specified row number has to be available. If not
// NewItem has to be used to add a new row
throw new ArgumentException("Row specified is not available");
} // if (rowNum...
string[] colValues = (values as string).Split(',');
// set the specified row
DataRow row = table.Rows[rowNumber];
for (int i = 0; i < colValues.Length; i++)
{
row[i] = colValues[i];
}
// Update the table
if (ShouldProcess(path, "SetItem"))
{
da.Update(ds, tableName);
}
}
The ItemExists method is called by the PowerShell engine when a user calls the T:Microsoft.PowerShell.Commands.Test-Path cmdlet. The method determines whether there is an item at the specified path. If the item does exist, the method passes it back to the PowerShell engine by calling WriteItemObject.
protected override bool ItemExists(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}
// Obtain type, table name and row number from path
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out rowNumber);
DatabaseTableInfo table = GetTable(tableName);
if (type == PathType.Table)
{
// if specified path represents a table then DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo should
// exist for the table and then specified row number must be within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}
return false;
}
The IsValidPath method checks whether the specified path is syntactically valid for the current provider. It does not check whether an item exists at the path.
protected override bool IsValidPath(string path)
{
bool result = true;
// check if the path is null or empty
if (String.IsNullOrEmpty(path))
{
result = false;
}
// convert all separators in the path to a uniform one
path = NormalizePath(path);
// split the path into individual chunks
string[] pathChunks = path.Split(pathSeparator.ToCharArray());
foreach (string pathChunk in pathChunks)
{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
}
A typical real-world provider is capable of supporting items that contain other items, and of moving items from one path to another within the drive. For an example of a provider that supports containers, see Writing a container provider. For an example of a provider that supports moving items, see Writing a navigation provider.
