Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This topic describes how to implement the methods of a Windows PowerShell provider that support nested containers (multi-level data stores), moving items, and relative paths. A navigation provider must derive from the System.Management.Automation.Provider.NavigationCmdletProvider 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 AccessDBProviderSample05.
For more information about Windows PowerShell providers, see Windows PowerShell Provider Overview.
Implementing navigation methods
The System.Management.Automation.Provider.NavigationCmdletProvider class implements methods that support nested containers, relative paths, and moving items. For a complete list of these methods, see NavigationCmdletProvider Methods.
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 System.Management.Automation.Provider.DriveCmdletProvider class that create and remove drives. This topic also does not cover how to implement methods exposed by the System.Management.Automation.Provider.ItemCmdletProvider or System.Management.Automation.Provider.ContainerCmdletProvider classes. For an example that shows how to implement item cmdlets, see Writing an item provider. For an example that shows how to implement container cmdlets, see Writing a container provider.
Declaring the provider class
Declare the provider to derive from the System.Management.Automation.Provider.NavigationCmdletProvider class, and decorate it with the System.Management.Automation.Provider.CmdletProviderAttribute.
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider
{
}
Implementing IsItemContainer
The System.Management.Automation.Provider.NavigationCmdletProvider.IsItemContainer* method checks whether the item at the specified path is a container.
protected override bool IsItemContainer(string path)
{
if (PathIsDrive(path))
{
return true;
}
string[] pathChunks = ChunkPath(path);
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out rowNumber);
if (type == PathType.Table)
{
foreach (DatabaseTableInfo ti in GetTables())
{
if (string.Equals(ti.Name, tableName, StringComparison.OrdinalIgnoreCase))
{
return true;
}
} // foreach (DatabaseTableInfo...
} // if (pathChunks...
return false;
}
Implementing GetChildName
The System.Management.Automation.Provider.NavigationCmdletProvider.GetChildName* method gets the name property of the child item at the specified path. If the item at the specified path is not a child of a container, then this method should return the path.
protected override string GetChildName(string path)
{
if (PathIsDrive(path))
{
return path;
}
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out rowNumber);
if (type == PathType.Table)
{
return tableName;
}
else if (type == PathType.Row)
{
return rowNumber.ToString(CultureInfo.CurrentCulture);
}
else
{
ThrowTerminatingInvalidPathException(path);
}
return null;
}
Implementing GetParentPath
The System.Management.Automation.Provider.NavigationCmdletProvider.GetParentPath* method gets the path of the parent of the item at the specified path. If the item at the specified path is the root of the data store (so it has no parent), then this method should return the root path.
protected override string GetParentPath(string path, string root)
{
// If root is specified then the path has to contain
// the root. If not nothing should be returned
if (!String.IsNullOrEmpty(root))
{
if (!path.Contains(root))
{
return null;
}
}
return path.Substring(0, path.LastIndexOf(pathSeparator, StringComparison.OrdinalIgnoreCase));
}
Implementing MakePath
The System.Management.Automation.Provider.NavigationCmdletProvider.MakePath* method joins a specified parent path and a specified child path to create a provider-internal path (for information about path types that providers can support, see Windows PowerShell Provider Overview. The PowerShell engine calls this method when a user calls the Microsoft.PowerShell.Commands.JoinPathCommand cmdlet.
protected override string MakePath(string parent, string child)
{
string result;
string normalParent = NormalizePath(parent);
normalParent = RemoveDriveFromPath(normalParent);
string normalChild = NormalizePath(child);
normalChild = RemoveDriveFromPath(normalChild);
if (String.IsNullOrEmpty(normalParent) && String.IsNullOrEmpty(normalChild))
{
result = String.Empty;
}
else if (String.IsNullOrEmpty(normalParent) && !String.IsNullOrEmpty(normalChild))
{
result = normalChild;
}
else if (!String.IsNullOrEmpty(normalParent) && String.IsNullOrEmpty(normalChild))
{
if (normalParent.EndsWith(pathSeparator, StringComparison.OrdinalIgnoreCase))
{
result = normalParent;
}
else
{
result = normalParent + pathSeparator;
}
} // else if (!String...
else
{
if (!normalParent.Equals(String.Empty) &&
!normalParent.EndsWith(pathSeparator, StringComparison.OrdinalIgnoreCase))
{
result = normalParent + pathSeparator;
}
else
{
result = normalParent;
}
if (normalChild.StartsWith(pathSeparator, StringComparison.OrdinalIgnoreCase))
{
result += normalChild.Substring(1);
}
else
{
result += normalChild;
}
} // else
return result;
}
Implementing NormalizeRelativePath
The System.Management.Automation.Provider.NavigationCmdletProvider.NormalizeRelativePath* method takes path and basepath parameters, and returns a normalized path that is equivalent to the path parameter and relative to the basepath parameter.
protected override string NormalizeRelativePath(string path,
string basepath)
{
// Normalize the paths first
string normalPath = NormalizePath(path);
normalPath = RemoveDriveFromPath(normalPath);
string normalBasePath = NormalizePath(basepath);
normalBasePath = RemoveDriveFromPath(normalBasePath);
if (String.IsNullOrEmpty(normalBasePath))
{
return normalPath;
}
else
{
if (!normalPath.Contains(normalBasePath))
{
return null;
}
return normalPath.Substring(normalBasePath.Length + pathSeparator.Length);
}
}
Implementing MoveItem
The System.Management.Automation.Provider.NavigationCmdletProvider.MoveItem* method moves an item from the specified path to the specified destination path. The PowerShell engine calls this method when a user calls the Microsoft.PowerShell.Commands.MoveItemCommand cmdlet.
protected override void MoveItem(string path, string destination)
{
// Get type, table name and rowNumber from the path
string tableName, destTableName;
int rowNumber, destRowNumber;
PathType type = GetNamesFromPath(path, out tableName, out rowNumber);
PathType destType = GetNamesFromPath(destination, out destTableName,
out destRowNumber);
if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}
if (destType == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(destination);
}
if (type == PathType.Table)
{
ArgumentException e = new ArgumentException("Move not supported for tables");
WriteError(new ErrorRecord(e, "MoveNotSupported",
ErrorCategory.InvalidArgument, path));
throw e;
}
else
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);
OdbcDataAdapter dda = GetAdapterForTable(destTableName);
if (dda == null)
{
return;
}
DataSet dds = GetDataSetForTable(dda, destTableName);
DataTable destTable = GetDataTable(dds, destTableName);
DataRow row = table.Rows[rowNumber];
if (destType == PathType.Table)
{
DataRow destRow = destTable.NewRow();
destRow.ItemArray = row.ItemArray;
}
else
{
DataRow destRow = destTable.Rows[destRowNumber];
destRow.ItemArray = row.ItemArray;
}
// Update the changes
if (ShouldProcess(path, "MoveItem"))
{
WriteItemObject(row, path, false);
dda.Update(dds, destTableName);
}
}
}