diff --git a/reference/docs-conceptual/developer/prog-guide/accessdbprovidersample03-code-sample.md b/reference/docs-conceptual/developer/prog-guide/accessdbprovidersample03-code-sample.md
index b40546c7e516..38069e83be6b 100644
--- a/reference/docs-conceptual/developer/prog-guide/accessdbprovidersample03-code-sample.md
+++ b/reference/docs-conceptual/developer/prog-guide/accessdbprovidersample03-code-sample.md
@@ -21,975 +21,6 @@ This provider that can manipulate the data in a data store.
## Code Sample
-```csharp
-using System;
-using System.IO;
-using System.Data;
-using System.Data.Odbc;
-using System.Collections.ObjectModel;
-using System.Text;
-using System.Diagnostics;
-using System.Text.RegularExpressions;
-using System.Management.Automation;
-using System.Management.Automation.Provider;
-using System.ComponentModel;
-using System.Globalization;
-
-namespace Microsoft.Samples.PowerShell.Providers
-{
- #region AccessDBProvider
-
- ///
- /// A PowerShell Provider which acts upon a access database.
- ///
- ///
- /// This example implements the item overloads.
- ///
- [CmdletProvider("AccessDB", ProviderCapabilities.None)]
-
- public class AccessDBProvider : ItemCmdletProvider
- {
- #region Drive Manipulation
-
- ///
- /// Create a new drive. Create a connection to the database file and set
- /// the Connection property in the PSDriveInfo.
- ///
- ///
- /// Information describing the drive to add.
- ///
- /// The added drive.
- protected override PSDriveInfo NewDrive(PSDriveInfo drive)
- {
- // check if drive object is null
- if (drive == null)
- {
- WriteError(new ErrorRecord(
- new ArgumentNullException("drive"),
- "NullDrive",
- ErrorCategory.InvalidArgument,
- null)
- );
-
- return null;
- }
-
- // check if drive root is not null or empty
- // and if its an existing file
- if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root) == false))
- {
- WriteError(new ErrorRecord(
- new ArgumentException("drive.Root"),
- "NoRoot",
- ErrorCategory.InvalidArgument,
- drive)
- );
-
- return null;
- }
-
- // create a new drive and create an ODBC connection to the new drive
- AccessDBPSDriveInfo accessDBPSDriveInfo = new AccessDBPSDriveInfo(drive);
-
- OdbcConnectionStringBuilder builder = new OdbcConnectionStringBuilder();
-
- builder.Driver = "Microsoft Access Driver (*.mdb)";
- builder.Add("DBQ", drive.Root);
-
- OdbcConnection conn = new OdbcConnection(builder.ConnectionString);
- conn.Open();
- accessDBPSDriveInfo.Connection = conn;
-
- return accessDBPSDriveInfo;
- } // NewDrive
-
- ///
- /// Removes a drive from the provider.
- ///
- /// The drive to remove.
- /// The drive removed.
- protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
- {
- // check if drive object is null
- if (drive == null)
- {
- WriteError(new ErrorRecord(
- new ArgumentNullException("drive"),
- "NullDrive",
- ErrorCategory.InvalidArgument,
- drive)
- );
-
- return null;
- }
-
- // close ODBC connection to the drive
- AccessDBPSDriveInfo accessDBPSDriveInfo = drive as AccessDBPSDriveInfo;
-
- if (accessDBPSDriveInfo == null)
- {
- return null;
- }
- accessDBPSDriveInfo.Connection.Close();
-
- return accessDBPSDriveInfo;
- } // RemoveDrive
-
- #endregion Drive Manipulation
-
- #region Item Methods
-
- ///
- /// Retrieves an item using the specified path.
- ///
- /// The path to the item to return.
- 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);
- }
-
- } // GetItem
-
- ///
- /// Set the content of a row of data specified by the supplied path
- /// parameter.
- ///
- /// Specifies the path to the row whose columns
- /// will be updated.
- /// Comma separated string of values
- 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);
- }
-
- } // SetItem
-
- ///
- /// Test to see if the specified item exists.
- ///
- /// The path to the item to verify.
- /// True if the item is found.
- 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;
-
- } // ItemExists
-
- ///
- /// Test to see if the specified path is syntactically valid.
- ///
- /// The path to validate.
- /// True if the specified path is valid.
- 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;
- } // IsValidPath
-
- #endregion Item Overloads
-
- #region Helper Methods
-
- ///
- /// Checks if a given path is actually a drive name.
- ///
- /// The path to check.
- ///
- /// True if the path given represents a drive, false otherwise.
- ///
- private bool PathIsDrive(string path)
- {
- // Remove the drive name and first path separator. If the
- // path is reduced to nothing, it is a drive. Also if its
- // just a drive then there wont be any path separators
- if (String.IsNullOrEmpty(
- path.Replace(this.PSDriveInfo.Root, "")) ||
- String.IsNullOrEmpty(
- path.Replace(this.PSDriveInfo.Root + pathSeparator, ""))
-
- )
- {
- return true;
- }
- else
- {
- return false;
- }
- } // PathIsDrive
-
- ///
- /// Breaks up the path into individual elements.
- ///
- /// The path to split.
- /// An array of path segments.
- private string[] ChunkPath(string path)
- {
- // Normalize the path before splitting
- string normalPath = NormalizePath(path);
-
- // Return the path with the drive name and first path
- // separator character removed, split by the path separator.
- string pathNoDrive = normalPath.Replace(this.PSDriveInfo.Root
- + pathSeparator, "");
-
- return pathNoDrive.Split(pathSeparator.ToCharArray());
- } // ChunkPath
-
- ///
- /// Adapts the path, making sure the correct path separator
- /// character is used.
- ///
- ///
- ///
- private string NormalizePath(string path)
- {
- string result = path;
-
- if (!String.IsNullOrEmpty(path))
- {
- result = path.Replace("/", pathSeparator);
- }
-
- return result;
- } // NormalizePath
-
- ///
- /// Chunks the path and returns the table name and the row number
- /// from the path
- ///
- /// Path to chunk and obtain information
- /// Name of the table as represented in the
- /// path
- /// Row number obtained from the path
- /// what the path represents
- private PathType GetNamesFromPath(string path, out string tableName, out int rowNumber)
- {
- PathType retVal = PathType.Invalid;
- rowNumber = -1;
- tableName = null;
-
- // Check if the path specified is a drive
- if (PathIsDrive(path))
- {
- return PathType.Database;
- }
-
- // chunk the path into parts
- string[] pathChunks = ChunkPath(path);
-
- switch (pathChunks.Length)
- {
- case 1:
- {
- string name = pathChunks[0];
-
- if (TableNameIsValid(name))
- {
- tableName = name;
- retVal = PathType.Table;
- }
- }
- break;
-
- case 2:
- {
- string name = pathChunks[0];
-
- if (TableNameIsValid(name))
- {
- tableName = name;
- }
-
- int number = SafeConvertRowNumber(pathChunks[1]);
-
- if (number >= 0)
- {
- rowNumber = number;
- retVal = PathType.Row;
- }
- else
- {
- WriteError(new ErrorRecord(
- new ArgumentException("Row number is not valid"),
- "RowNumberNotValid",
- ErrorCategory.InvalidArgument,
- path));
- }
- }
- break;
-
- default:
- {
- WriteError(new ErrorRecord(
- new ArgumentException("The path supplied has too many segments"),
- "PathNotValid",
- ErrorCategory.InvalidArgument,
- path));
- }
- break;
- } // switch(pathChunks...
-
- return retVal;
- } // GetNamesFromPath
-
- ///
- /// Throws an argument exception stating that the specified path does
- /// not represent either a table or a row
- ///
- /// path which is invalid
- private void ThrowTerminatingInvalidPathException(string path)
- {
- StringBuilder message = new StringBuilder("Path must represent either a table or a row :");
- message.Append(path);
-
- throw new ArgumentException(message.ToString());
- }
-
- ///
- /// Retrieve the list of tables from the database.
- ///
- ///
- /// Collection of DatabaseTableInfo objects, each object representing
- /// information about one database table
- ///
- private Collection GetTables()
- {
- Collection results =
- new Collection();
-
- // using ODBC connection to the database and get the schema of tables
- AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
-
- if (di == null)
- {
- return null;
- }
-
- OdbcConnection connection = di.Connection;
- DataTable dt = connection.GetSchema("Tables");
- int count;
-
- // iterate through all rows in the schema and create DatabaseTableInfo
- // objects which represents a table
- foreach (DataRow dr in dt.Rows)
- {
- String tableName = dr["TABLE_NAME"] as String;
- DataColumnCollection columns = null;
-
- // find the number of rows in the table
- try
- {
- String cmd = "Select count(*) from \"" + tableName + "\"";
- OdbcCommand command = new OdbcCommand(cmd, connection);
-
- count = (Int32)command.ExecuteScalar();
- }
- catch
- {
- count = 0;
- }
-
- // create DatabaseTableInfo object representing the table
- DatabaseTableInfo table =
- new DatabaseTableInfo(dr, tableName, count, columns);
-
- results.Add(table);
- } // foreach (DataRow...
-
- return results;
- } // GetTables
-
- ///
- /// Return row information from a specified table.
- ///
- /// The name of the database table from
- /// which to retrieve rows.
- /// Collection of row information objects.
- private Collection GetRows(string tableName)
- {
- Collection results =
- new Collection();
-
- // Obtain rows in the table and add it to the collection
- try
- {
- OdbcDataAdapter da = GetAdapterForTable(tableName);
-
- if (da == null)
- {
- return null;
- }
-
- DataSet ds = GetDataSetForTable(da, tableName);
- DataTable table = GetDataTable(ds, tableName);
-
- int i = 0;
- foreach (DataRow row in table.Rows)
- {
- results.Add(new DatabaseRowInfo(row, i.ToString(CultureInfo.CurrentCulture)));
- i++;
- } // foreach (DataRow...
- }
- catch (Exception e)
- {
- WriteError(new ErrorRecord(e, "CannotAccessSpecifiedRows",
- ErrorCategory.InvalidOperation, tableName));
- }
-
- return results;
-
- } // GetRows
-
- ///
- /// Retrieve information about a single table.
- ///
- /// The table for which to retrieve
- /// data.
- /// Table information.
- private DatabaseTableInfo GetTable(string tableName)
- {
- foreach (DatabaseTableInfo table in GetTables())
- {
- if (String.Equals(tableName, table.Name, StringComparison.OrdinalIgnoreCase))
- {
- return table;
- }
- }
-
- return null;
- } // GetTable
-
- ///
- /// Obtain a data adapter for the specified Table
- ///
- /// Name of the table to obtain the
- /// adapter for
- /// Adapter object for the specified table
- /// An adapter serves as a bridge between a DataSet (in memory
- /// representation of table) and the data source
- private OdbcDataAdapter GetAdapterForTable(string tableName)
- {
- OdbcDataAdapter da = null;
- AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
-
- if (di == null || !TableNameIsValid(tableName) || !TableIsPresent(tableName))
- {
- return null;
- }
-
- OdbcConnection connection = di.Connection;
-
- try
- {
- // Create a odbc data adapter. This can be sued to update the
- // data source with the records that will be created here
- // using data sets
- string sql = "Select * from " + tableName;
- da = new OdbcDataAdapter(new OdbcCommand(sql, connection));
-
- // Create a odbc command builder object. This will create sql
- // commands automatically for a single table, thus
- // eliminating the need to create new sql statements for
- // every operation to be done.
- OdbcCommandBuilder cmd = new OdbcCommandBuilder(da);
-
- // Open the connection if its not already open
- if (connection.State != ConnectionState.Open)
- {
- connection.Open();
- }
- }
- catch (Exception e)
- {
- WriteError(new ErrorRecord(e, "CannotAccessSpecifiedTable",
- ErrorCategory.InvalidOperation, tableName));
- }
-
- return da;
- } // GetAdapterForTable
-
- ///
- /// Gets the DataSet (in memory representation) for the table
- /// for the specified adapter
- ///
- /// Adapter to be used for obtaining
- /// the table
- /// Name of the table for which a
- /// DataSet is required
- /// The DataSet with the filled in schema
- private DataSet GetDataSetForTable(OdbcDataAdapter adapter, string tableName)
- {
- Debug.Assert(adapter != null);
-
- // Create a dataset object which will provide an in-memory
- // representation of the data being worked upon in the
- // data source.
- DataSet ds = new DataSet();
-
- // Create a table named "Table" which will contain the same
- // schema as in the data source.
- //adapter.FillSchema(ds, SchemaType.Source);
- adapter.Fill(ds, tableName);
- ds.Locale = CultureInfo.InvariantCulture;
-
- return ds;
- } //GetDataSetForTable
-
- ///
- /// Get the DataTable object which can be used to operate on
- /// for the specified table in the data source
- ///
- /// DataSet object which contains the tables
- /// schema
- /// Name of the table
- /// Corresponding DataTable object representing
- /// the table
- ///
- private DataTable GetDataTable(DataSet ds, string tableName)
- {
- Debug.Assert(ds != null);
- Debug.Assert(tableName != null);
-
- DataTable table = ds.Tables[tableName];
- table.Locale = CultureInfo.InvariantCulture;
-
- return table;
- } // GetDataTable
-
- ///
- /// Retrieves a single row from the named table.
- ///
- /// The table that contains the
- /// numbered row.
- /// The index of the row to return.
- /// The specified table row.
- private DatabaseRowInfo GetRow(string tableName, int row)
- {
- Collection di = GetRows(tableName);
-
- // if the row is invalid write an appropriate error else return the
- // corresponding row information
- if (row < di.Count && row >= 0)
- {
- return di[row];
- }
- else
- {
- WriteError(new ErrorRecord(
- new ItemNotFoundException(),
- "RowNotFound",
- ErrorCategory.ObjectNotFound,
- row.ToString(CultureInfo.CurrentCulture))
- );
- }
-
- return null;
- } // GetRow
-
- ///
- /// Method to safely convert a string representation of a row number
- /// into its Int32 equivalent
- ///
- /// String representation of the row
- /// number
- /// If there is an exception, -1 is returned
- private int SafeConvertRowNumber(string rowNumberAsStr)
- {
- int rowNumber = -1;
- try
- {
- rowNumber = Convert.ToInt32(rowNumberAsStr, CultureInfo.CurrentCulture);
- }
- catch (FormatException fe)
- {
- WriteError(new ErrorRecord(fe, "RowStringFormatNotValid",
- ErrorCategory.InvalidData, rowNumberAsStr));
- }
- catch (OverflowException oe)
- {
- WriteError(new ErrorRecord(oe, "RowStringConversionToNumberFailed",
- ErrorCategory.InvalidData, rowNumberAsStr));
- }
-
- return rowNumber;
- } // SafeConvertRowNumber
-
- ///
- /// Check if a table name is valid
- ///
- /// Table name to validate
- /// Helps to check for SQL injection attacks
- private bool TableNameIsValid(string tableName)
- {
- Regex exp = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
-
- if (exp.IsMatch(tableName))
- {
- return true;
- }
- WriteError(new ErrorRecord(
- new ArgumentException("Table name not valid"), "TableNameNotValid",
- ErrorCategory.InvalidArgument, tableName));
- return false;
- } // TableNameIsValid
-
- ///
- /// Checks to see if the specified table is present in the
- /// database
- ///
- /// Name of the table to check
- /// true, if table is present, false otherwise
- private bool TableIsPresent(string tableName)
- {
- // using ODBC connection to the database and get the schema of tables
- AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
- if (di == null)
- {
- return false;
- }
-
- OdbcConnection connection = di.Connection;
- DataTable dt = connection.GetSchema("Tables");
-
- // check if the specified tableName is available
- // in the list of tables present in the database
- foreach (DataRow dr in dt.Rows)
- {
- string name = dr["TABLE_NAME"] as string;
- if (name.Equals(tableName, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- WriteError(new ErrorRecord(
- new ArgumentException("Specified Table is not present in database"), "TableNotAvailable",
- ErrorCategory.InvalidArgument, tableName));
-
- return false;
- }// TableIsPresent
-
- #endregion Helper Methods
-
- #region Private Properties
-
- private string pathSeparator = "\\";
- private static string pattern = @"^[a-z]+[0-9]*_*$";
-
- private enum PathType { Database, Table, Row, Invalid };
-
- #endregion Private Properties
- }
-
- #endregion AccessDBProvider
-
- #region Helper Classes
-
- #region AccessDBPSDriveInfo
-
- ///
- /// Any state associated with the drive should be held here.
- /// In this case, it's the connection to the database.
- ///
- internal class AccessDBPSDriveInfo : PSDriveInfo
- {
- private OdbcConnection connection;
-
- ///
- /// ODBC connection information.
- ///
- public OdbcConnection Connection
- {
- get { return connection; }
- set { connection = value; }
- }
-
- ///
- /// Constructor that takes one argument
- ///
- /// Drive provided by this provider
- public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
- : base(driveInfo)
- { }
-
- } // class AccessDBPSDriveInfo
-
- #endregion AccessDBPSDriveInfo
-
- #region DatabaseTableInfo
-
- ///
- /// Contains information specific to the database table.
- /// Similar to the DirectoryInfo class.
- ///
- public class DatabaseTableInfo
- {
- ///
- /// Row from the "tables" schema
- ///
- public DataRow Data
- {
- get
- {
- return data;
- }
- set
- {
- data = value;
- }
- }
- private DataRow data;
-
- ///
- /// The table name.
- ///
- public string Name
- {
- get
- {
- return name;
- }
- set
- {
- name = value;
- }
- }
- private String name;
-
- ///
- /// The number of rows in the table.
- ///
- public int RowCount
- {
- get
- {
- return rowCount;
- }
- set
- {
- rowCount = value;
- }
- }
- private int rowCount;
-
- ///
- /// The column definitions for the table.
- ///
- public DataColumnCollection Columns
- {
- get
- {
- return columns;
- }
- set
- {
- columns = value;
- }
- }
- private DataColumnCollection columns;
-
- ///
- /// Constructor.
- ///
- /// The row definition.
- /// The table name.
- /// The number of rows in the table.
- /// Information on the column tables.
- public DatabaseTableInfo(DataRow row, string name, int rowCount,
- DataColumnCollection columns)
- {
- Name = name;
- Data = row;
- RowCount = rowCount;
- Columns = columns;
- } // DatabaseTableInfo
- } // class DatabaseTableInfo
-
- #endregion DatabaseTableInfo
-
- #region DatabaseRowInfo
-
- ///
- /// Contains information specific to an individual table row.
- /// Analogous to the FileInfo class.
- ///
- public class DatabaseRowInfo
- {
- ///
- /// Row data information.
- ///
- public DataRow Data
- {
- get
- {
- return data;
- }
- set
- {
- data = value;
- }
- }
- private DataRow data;
-
- ///
- /// The row index.
- ///
- public string RowNumber
- {
- get
- {
- return rowNumber;
- }
- set
- {
- rowNumber = value;
- }
- }
- private string rowNumber;
-
- ///
- /// Constructor.
- ///
- /// The row information.
- /// The row index.
- public DatabaseRowInfo(DataRow row, string name)
- {
- RowNumber = name;
- Data = row;
- } // DatabaseRowInfo
- } // class DatabaseRowInfo
-
- #endregion DatabaseRowInfo
-
- #endregion Helper Classes
-}
-```
-
:::code language="csharp" source="~/../powershell-sdk-samples/SDK-2.0/csharp/AccessDBProviderSample03/AccessDBProviderSample03.cs" range="11-976":::
## See Also