Udostępnij za pośrednictwem


Tworzenie dostawcy zawartości programu Windows PowerShell

W tym temacie opisano sposób tworzenia dostawcy programu Windows PowerShell, który umożliwia użytkownikowi manipulowanie zawartością elementów w magazynie danych. W związku z tym dostawca, który może manipulować zawartością elementów, jest określany jako dostawca zawartości programu Windows PowerShell.

Uwaga

Możesz pobrać plik źródłowy języka C# (AccessDBSampleProvider06.cs) dla tego dostawcy przy użyciu zestawu Microsoft Windows Software Development Kit dla systemów Windows Vista i .NET Framework 3.0 Runtime Components. Aby uzyskać instrukcje pobierania, zobacz How to Install Windows PowerShell (Jak zainstalować program Windows PowerShell) i Download the Windows PowerShell SDK (Pobieranie zestawu Windows PowerShell SDK). Pobrane pliki źródłowe są dostępne w katalogu <Przykłady programu PowerShell>. Aby uzyskać więcej informacji na temat innych implementacji dostawców programu Windows PowerShell, zobacz Projektowanie dostawcy programu Windows PowerShell.

Definiowanie klasy dostawcy zawartości programu Windows PowerShell

Dostawca zawartości programu Windows PowerShell musi utworzyć klasę .NET, która obsługuje interfejs System.Management.Automation.Provider.IContentCmdletProvider. Oto definicja klasy dostawcy elementów opisana w tej sekcji.

[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider, IContentCmdletProvider

Należy pamiętać, że w tej definicji klasy atrybut System.Management.Automation.Provider.CmdletProviderAttribute zawiera dwa parametry. Pierwszy parametr określa przyjazną dla użytkownika nazwę dostawcy, który jest używany przez program Windows PowerShell. Drugi parametr określa funkcje specyficzne dla środowiska Windows PowerShell, które dostawca uwidacznia środowisko uruchomieniowe programu Windows PowerShell podczas przetwarzania poleceń. W przypadku tego dostawcy nie ma dodanych funkcji specyficznych dla programu Windows PowerShell.

Definiowanie funkcji klasy bazowej

Zgodnie z opisem w Design Your Windows PowerShell Provider, klasa System.Management.Automation.Provider.NavigationCmdletProvider pochodzi z kilku innych klas, które dostarczyły różnych funkcji dostawcy. Dlatego dostawca zawartości programu Windows PowerShell zwykle definiuje wszystkie funkcje udostępniane przez te klasy.

Aby uzyskać więcej informacji na temat implementowania funkcji dodawania informacji inicjowania specyficznych dla sesji i udostępniania zasobów używanych przez dostawcę, zobacz Tworzenie podstawowego dostawcy programu Windows PowerShell. Jednak większość dostawców, w tym dostawcy opisanego tutaj, może użyć domyślnej implementacji tej funkcji udostępnianej przez program Windows PowerShell.

Aby uzyskać dostęp do magazynu danych, dostawca musi zaimplementować metody System.Management.Automation.Provider.DriveCmdletProvider klasy bazowej. Aby uzyskać więcej informacji na temat implementowania tych metod, zobacz Tworzenie dostawcy dysków programu Windows PowerShell.

Aby manipulować elementami magazynu danych, takimi jak pobieranie, ustawianie i czyszczenie elementów, dostawca musi zaimplementować metody udostępniane przez klasę bazową System.Management.Automation.Provider.ItemCmdletProvider. Aby uzyskać więcej informacji na temat implementowania tych metod, zobacz Tworzenie dostawcy elementów programu Windows PowerShell.

Aby pracować nad wielowarstwowymi magazynami danych, dostawca musi zaimplementować metody udostępniane przez klasę bazową System.Management.Automation.Provider.ContainerCmdlet Provider. Aby uzyskać więcej informacji na temat implementowania tych metod, zobacz Tworzenie dostawcy kontenera programu Windows PowerShell.

Aby obsługiwać polecenia cykliczne, zagnieżdżone kontenery i ścieżki względne, dostawca musi zaimplementować klasę bazową System.Management.Automation.Provider.NavigationCmdletProvider. Ponadto ten dostawca zawartości programu Windows PowerShell może dołączyć System.Management.Automation.Provider.IContentCmdletProvider interfejs do interfejsu System.Management.Automation.Provider.NavigationCmdletProvider klasy bazowej i dlatego musi zaimplementować metody dostarczone przez tę klasę. Aby uzyskać więcej informacji, zobacz implementowanie tych metod, zobacz Implement a Navigation Windows PowerShell Provider.

Implementowanie czytnika zawartości

Aby odczytać zawartość z elementu, dostawca musi zaimplementować klasę czytnika zawartości pochodzącą z System.Management.Automation.Provider.IContentReader. Czytnik zawartości dla tego dostawcy umożliwia dostęp do zawartości wiersza w tabeli danych. Klasa czytnika zawartości definiuje metodę Read, która pobiera dane z wskazanego wiersza i zwraca listę reprezentującą te dane, metodę Seek, która przenosi czytnik zawartości, metodę Close, która zamyka czytnik zawartości i metodę Dispose.

public class AccessDBContentReader : IContentReader
{
    // A provider instance is required so as to get "content"
    private AccessDBProvider provider;
    private string path;
    private long currentOffset;

    internal AccessDBContentReader(string path, AccessDBProvider provider)
    {
        this.path = path;
        this.provider = provider;
    }

    /// <summary>
    /// Read the specified number of rows from the source.
    /// </summary>
    /// <param name="readCount">The number of items to 
    /// return.</param>
    /// <returns>An array of elements read.</returns>
    public IList Read(long readCount)
    {
        // Read the number of rows specified by readCount and increment
        // offset
        string tableName;
        int rowNumber;
        PathType type = provider.GetNamesFromPath(path, out tableName, out rowNumber);

        Collection<DatabaseRowInfo> rows =
            provider.GetRows(tableName);
        Collection<DataRow> results = new Collection<DataRow>();

        if (currentOffset < 0 || currentOffset >= rows.Count)
        {
            return null;
        }

        int rowsRead = 0;

        while (rowsRead < readCount && currentOffset < rows.Count)
        {
            results.Add(rows[(int)currentOffset].Data);
            rowsRead++;
            currentOffset++;
        }

        return results;
    } // Read

    /// <summary>
    /// Moves the content reader specified number of rows from the 
    /// origin
    /// </summary>
    /// <param name="offset">Number of rows to offset</param>
    /// <param name="origin">Starting row from which to offset</param>
    public void Seek(long offset, System.IO.SeekOrigin origin)
    {
        // get the number of rows in the table which will help in
        // calculating current position
        string tableName;
        int rowNumber;

        PathType type = provider.GetNamesFromPath(path, out tableName, out rowNumber);

        if (type == PathType.Invalid)
        {
            throw new ArgumentException("Path specified must represent a table or a row :" + path);
        }

        if (type == PathType.Table)
        {
            Collection<DatabaseRowInfo> rows = provider.GetRows(tableName);

            int numRows = rows.Count;

            if (offset > rows.Count)
            {
                throw new
                       ArgumentException(
                           "Offset cannot be greater than the number of rows available"
                                        );
            }

            if (origin == System.IO.SeekOrigin.Begin)
            {
                // starting from Beginning with an index 0, the current offset
                // has to be advanced to offset - 1
                currentOffset = offset - 1;
            }
            else if (origin == System.IO.SeekOrigin.End)
            {
                // starting from the end which is numRows - 1, the current
                // offset is so much less than numRows - 1
                currentOffset = numRows - 1 - offset;
            }
            else
            {
                // calculate from the previous value of current offset
                // advancing forward always
                currentOffset += offset;
            }
        } // if (type...
        else
        {
            // for row, the offset will always be set to 0
            currentOffset = 0;
        }

    } // Seek

    /// <summary>
    /// Closes the content reader, so all members are reset
    /// </summary>
    public void Close()
    {
        Dispose();
    } // Close

    /// <summary>
    /// Dispose any resources being used
    /// </summary>
    public void Dispose()
    {
        Seek(0, System.IO.SeekOrigin.Begin);
        
        GC.SuppressFinalize(this);
    } // Dispose
} // AccessDBContentReader

Implementowanie składnika zapisywania zawartości

Aby zapisać zawartość w elemencie, dostawca musi zaimplementować klasę składnika zapisywania zawartości pochodzącą z System.Management.Automation.Provider.IContentWriter. Klasa składnika zapisywania zawartości definiuje metodę Write, która zapisuje określoną zawartość wiersza, metodę Seek, która przenosi składnik zapisywania zawartości, metodę Close, która zamyka składnik zapisywania zawartości i metodę Dispose.

public class AccessDBContentWriter : IContentWriter
{
    // A provider instance is required so as to get "content"
    private AccessDBProvider provider;
    private string path;
    private long currentOffset;

    internal AccessDBContentWriter(string path, AccessDBProvider provider)
    {
        this.path = path;
        this.provider = provider;
    }

    /// <summary>
    /// Write the specified row contents in the source
    /// </summary>
    /// <param name="content"> The contents to be written to the source.
    /// </param>
    /// <returns>An array of elements which were successfully written to 
    /// the source</returns>
    /// 
    public IList Write(IList content)
    {
        if (content == null)
        {
            return null;
        }

        // Get the total number of rows currently available it will 
        // determine how much to overwrite and how much to append at
        // the end
        string tableName;
        int rowNumber;
        PathType type = provider.GetNamesFromPath(path, out tableName, out rowNumber);

        if (type == PathType.Table)
        {
            OdbcDataAdapter da = provider.GetAdapterForTable(tableName);
            if (da == null)
            {
                return null;
            }

            DataSet ds = provider.GetDataSetForTable(da, tableName);
            DataTable table = provider.GetDataTable(ds, tableName);

            string[] colValues = (content[0] as string).Split(',');

            // set the specified row
            DataRow row = table.NewRow();

            for (int i = 0; i < colValues.Length; i++)
            {
                if (!String.IsNullOrEmpty(colValues[i]))
                {
                    row[i] = colValues[i];
                }
            }

            //table.Rows.InsertAt(row, rowNumber);
            // Update the table
            table.Rows.Add(row);
            da.Update(ds, tableName);
            
        }
        else 
        {
            throw new InvalidOperationException("Operation not supported. Content can be added only for tables");
        }

        return null;
    } // Write

    /// <summary>
    /// Moves the content reader specified number of rows from the 
    /// origin
    /// </summary>
    /// <param name="offset">Number of rows to offset</param>
    /// <param name="origin">Starting row from which to offset</param>
    public void Seek(long offset, System.IO.SeekOrigin origin)
    {
        // get the number of rows in the table which will help in
        // calculating current position
        string tableName;
        int rowNumber;

        PathType type = provider.GetNamesFromPath(path, out tableName, out rowNumber);

        if (type == PathType.Invalid)
        {
            throw new ArgumentException("Path specified should represent either a table or a row : " + path);
        }

        Collection<DatabaseRowInfo> rows =
               provider.GetRows(tableName);

        int numRows = rows.Count;

        if (offset > rows.Count)
        {
            throw new
                   ArgumentException(
                       "Offset cannot be greater than the number of rows available"
                                           );
        }

        if (origin == System.IO.SeekOrigin.Begin)
        {
            // starting from Beginning with an index 0, the current offset
            // has to be advanced to offset - 1
            currentOffset = offset - 1;
        }
        else if (origin == System.IO.SeekOrigin.End)
        {
            // starting from the end which is numRows - 1, the current
            // offset is so much less than numRows - 1
            currentOffset = numRows - 1 - offset;
        }
        else
        {
            // calculate from the previous value of current offset
            // advancing forward always
            currentOffset += offset;
        }

    } // Seek

    /// <summary>
    /// Closes the content reader, so all members are reset
    /// </summary>
    public void Close()
    {
        Dispose();
    } // Close

    /// <summary>
    /// Dispose any resources being used
    /// </summary>
    public void Dispose()
    {
        Seek(0, System.IO.SeekOrigin.Begin);

        GC.SuppressFinalize(this);
    } // Dispose
} // AccessDBContentWriter

Pobieranie czytnika zawartości

Aby pobrać zawartość z elementu, dostawca musi zaimplementować System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader* w celu obsługi polecenia cmdlet Get-Content. Ta metoda zwraca czytnik zawartości dla elementu znajdującego się w określonej ścieżce. Następnie można otworzyć obiekt czytelnika, aby odczytać zawartość.

Oto implementacja System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader* dla tej metody dla tego dostawcy.

public IContentReader GetContentReader(string path)
{
    string tableName;
    int rowNumber;

    PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

    if (type == PathType.Invalid)
    {
        ThrowTerminatingInvalidPathException(path);
    }
    else if (type == PathType.Row)
    {
        throw new InvalidOperationException("contents can be obtained only for tables");
    }

    return new AccessDBContentReader(path, this);
} // GetContentReader
public IContentReader GetContentReader(string path)
{
    string tableName;
    int rowNumber;

    PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

    if (type == PathType.Invalid)
    {
        ThrowTerminatingInvalidPathException(path);
    }
    else if (type == PathType.Row)
    {
        throw new InvalidOperationException("contents can be obtained only for tables");
    }

    return new AccessDBContentReader(path, this);
} // GetContentReader

Co należy pamiętać o implementowaniu elementu GetContentReader

Następujące warunki mogą mieć zastosowanie do implementacji System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader*:

Dołączanie parametrów dynamicznych do polecenia cmdlet Get-Content

Polecenie cmdlet Get-Content może wymagać dodatkowych parametrów, które są określane dynamicznie w czasie wykonywania. Aby zapewnić te parametry dynamiczne, dostawca zawartości programu Windows PowerShell musi zaimplementować metodę System.Management.Automation.Provider.IContentCmdletProvider.GetContentReaderdynamicparameters*. Ta metoda pobiera parametry dynamiczne dla elementu w wskazanej ścieżce i zwraca obiekt zawierający właściwości i pola z atrybutami analizowania podobnymi do klasy cmdlet lub System.Management.Automation.RuntimeDefinedParameterDictionary. Środowisko uruchomieniowe programu Windows PowerShell używa zwróconego obiektu w celu dodania parametrów do polecenia cmdlet.

Ten dostawca kontenera programu Windows PowerShell nie implementuje tej metody. Jednak poniższy kod jest domyślną implementacją tej metody.

public object GetContentReaderDynamicParameters(string path)
{
    return null;
}
public object GetContentReaderDynamicParameters(string path)
{
    return null;
}

Pobieranie składnika zapisywania zawartości

Aby zapisać zawartość w elemencie, dostawca musi zaimplementować System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter* w celu obsługi poleceń cmdlet Set-Content i Add-Content. Ta metoda zwraca składnik zapisywania zawartości dla elementu znajdującego się w określonej ścieżce.

Oto implementacja System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter* dla tej metody.

public IContentWriter GetContentWriter(string path)
{
    string tableName;
    int rowNumber;

    PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

    if (type == PathType.Invalid)
    {
        ThrowTerminatingInvalidPathException(path);
    }
    else if (type == PathType.Row)
    {
        throw new InvalidOperationException("contents can be added only to tables");
    }

    return new AccessDBContentWriter(path, this);
}
public IContentWriter GetContentWriter(string path)
{
    string tableName;
    int rowNumber;

    PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

    if (type == PathType.Invalid)
    {
        ThrowTerminatingInvalidPathException(path);
    }
    else if (type == PathType.Row)
    {
        throw new InvalidOperationException("contents can be added only to tables");
    }

    return new AccessDBContentWriter(path, this);
}

Co należy pamiętać o implementowaniu polecenia GetContentWriter

Następujące warunki mogą mieć zastosowanie do implementacji System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter*:

Dołączanie parametrów dynamicznych do poleceń cmdlet Add-Content i Set-Content

Polecenia cmdlet Add-Content i Set-Content mogą wymagać dodatkowych parametrów dynamicznych, które zostały dodane przez środowisko uruchomieniowe. Aby zapewnić te parametry dynamiczne, dostawca zawartości programu Windows PowerShell musi zaimplementować metodę System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriterDynamicParameters* metody . Ta metoda pobiera parametry dynamiczne dla elementu w wskazanej ścieżce i zwraca obiekt zawierający właściwości i pola z atrybutami analizowania podobnymi do klasy cmdlet lub System.Management.Automation.RuntimeDefinedParameterDictionary. Środowisko uruchomieniowe programu Windows PowerShell używa zwróconego obiektu w celu dodania parametrów do poleceń cmdlet.

Ten dostawca kontenera programu Windows PowerShell nie implementuje tej metody. Jednak poniższy kod jest domyślną implementacją tej metody.

public object GetContentWriterDynamicParameters(string path)
{
    return null;
}

Czyszczenie zawartości

Dostawca zawartości implementuje metodę System.Management.Automation.Provider.IContentCmdletProvider.ClearContent* w obsłudze polecenia cmdlet Clear-Content. Ta metoda usuwa zawartość elementu w określonej ścieżce, ale pozostawia element nienaruszony.

Oto implementacja metody System.Management.Automation.Provider.IContentCmdletProvider.ClearContent* dla tego dostawcy.

public void ClearContent(string path)
{
    string tableName;
    int rowNumber;

    PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

    if (type != PathType.Table)
    {
        WriteError(new ErrorRecord(
            new InvalidOperationException("Operation not supported. Content can be cleared only for table"),
                "NotValidRow", ErrorCategory.InvalidArgument,
                    path));
        return;
    }

    OdbcDataAdapter da = GetAdapterForTable(tableName);

    if (da == null)
    {
        return;
    }

    DataSet ds = GetDataSetForTable(da, tableName);
    DataTable table = GetDataTable(ds, tableName);

    // Clear contents at the specified location
    for (int i = 0; i < table.Rows.Count; i++)
    {
        table.Rows[i].Delete();
    }

    if (ShouldProcess(path, "ClearContent"))
    {
        da.Update(ds, tableName);
    }

} // ClearContent

Kwestie, które należy pamiętać o implementowaniu funkcji ClearContent

Następujące warunki mogą mieć zastosowanie do implementacji System.Management.Automation.Provider.IContentCmdletProvider.ClearContent*:

Dołączanie parametrów dynamicznych do polecenia cmdlet Clear-Content

Polecenie cmdlet Clear-Content może wymagać dodatkowych parametrów dynamicznych, które są dodawane w czasie wykonywania. Aby zapewnić te parametry dynamiczne, dostawca zawartości programu Windows PowerShell musi zaimplementować metodę System.Management.Automation.Provider.IContentCmdletProvider.ClearContentDynamicParameters* metody . Ta metoda pobiera parametry elementu w wskazanej ścieżce. Ta metoda pobiera parametry dynamiczne dla elementu w wskazanej ścieżce i zwraca obiekt zawierający właściwości i pola z atrybutami analizowania podobnymi do klasy cmdlet lub System.Management.Automation.RuntimeDefinedParameterDictionary. Środowisko uruchomieniowe programu Windows PowerShell używa zwróconego obiektu w celu dodania parametrów do polecenia cmdlet.

Ten dostawca kontenera programu Windows PowerShell nie implementuje tej metody. Jednak poniższy kod jest domyślną implementacją tej metody.

public object ClearContentDynamicParameters(string path)
{
    return null;
}
public object ClearContentDynamicParameters(string path)
{
    return null;
}

Przykładowy kod

Aby uzyskać pełny przykładowy kod, zobacz AccessDbProviderSample06 Code Sample.

Definiowanie typów obiektów i formatowanie

Podczas pisania dostawcy może być konieczne dodanie elementów członkowskich do istniejących obiektów lub zdefiniowanie nowych obiektów. Po wykonaniu tej czynności należy utworzyć plik Typy, którego program Windows PowerShell może użyć do identyfikowania elementów członkowskich obiektu i pliku Formatu, który definiuje sposób wyświetlania obiektu. Aby uzyskać więcej informacji, zobacz Rozszerzanie typów obiektów i formatowanie.

Kompilowanie dostawcy programu Windows PowerShell

Zobacz Jak rejestrować polecenia cmdlet, dostawcy i aplikacje hosta.

Testowanie dostawcy programu Windows PowerShell

Jeśli dostawca programu Windows PowerShell został zarejestrowany w programie Windows PowerShell, możesz go przetestować, uruchamiając obsługiwane polecenia cmdlet w wierszu polecenia. Na przykład przetestuj przykładowego dostawcę zawartości.

Użyj polecenia cmdlet Get-Content, aby pobrać zawartość określonego elementu w tabeli bazy danych na ścieżce określonej przez parametr Path. Parametr ReadCount określa liczbę elementów dla zdefiniowanego czytnika zawartości do odczytu (wartość domyślna 1). Po wpisie następującego polecenia polecenie cmdlet pobiera dwa wiersze (elementy) z tabeli i wyświetla ich zawartość. Zwróć uwagę, że następujące przykładowe dane wyjściowe używają fikcyjnej bazy danych programu Access.

Get-Content -Path mydb:\Customers -ReadCount 2
ID        : 1
FirstName : Eric
LastName  : Gruber
Email     : ericgruber@fabrikam.com
Title     : President
Company   : Fabrikam
WorkPhone : (425) 555-0100
Address   : 4567 Main Street
City      : Buffalo
State     : NY
Zip       : 98052
Country   : USA
ID        : 2
FirstName : Eva
LastName  : Corets
Email     : evacorets@cohowinery.com
Title     : Sales Representative
Company   : Coho Winery
WorkPhone : (360) 555-0100
Address   : 8910 Main Street
City      : Cabmerlot
State     : WA
Zip       : 98089
Country   : USA

Zobacz też

Tworzenie dostawców programu Windows PowerShell

projektowanie dostawcy programu Windows PowerShell

rozszerzanie typów obiektów i formatowanie

implementowanie dostawcy programu Windows PowerShell nawigacji

Jak rejestrować polecenia cmdlet, dostawcy i aplikacje hosta

zestaw SDK programu Windows PowerShell

Przewodnik programisty programu Windows PowerShell