Bagikan melalui


Membuat Penyedia Konten Windows PowerShell

Topik ini menjelaskan cara membuat penyedia Windows PowerShell yang memungkinkan pengguna memanipulasi konten item dalam penyimpanan data. Akibatnya, penyedia yang dapat memanipulasi konten item disebut sebagai penyedia konten Windows PowerShell.

Nota

Anda dapat mengunduh file sumber C# (AccessDBSampleProvider06.cs) untuk penyedia ini menggunakan Kit Pengembangan Perangkat Lunak Microsoft Windows untuk Komponen Runtime Windows Vista dan .NET Framework 3.0. Untuk petunjuk pengunduhan, lihat Cara Menginstal Windows PowerShell dan Mengunduh Windows PowerShell SDK. File sumber yang diunduh tersedia di <direktori Sampel PowerShell> . Untuk informasi selengkapnya tentang implementasi penyedia Windows PowerShell lainnya, lihat Merancang Penyedia Windows PowerShell Anda.

Menentukan kelas penyedia konten Windows PowerShell

Penyedia konten Windows PowerShell harus membuat kelas .NET yang mendukung antarmuka System.Management.Automation.Provider.IContentCmdletProvider . Berikut adalah definisi kelas untuk penyedia item yang dijelaskan di bagian ini.

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

Perhatikan bahwa dalam definisi kelas ini, atribut System.Management.Automation.Provider.CmdletProviderAttribute menyertakan dua parameter. Parameter pertama menentukan nama yang mudah digunakan untuk penyedia yang digunakan oleh Windows PowerShell. Parameter kedua menentukan kemampuan khusus Windows PowerShell yang diekspos penyedia ke runtime Windows PowerShell selama pemrosesan perintah. Untuk penyedia ini, tidak ada kemampuan khusus Windows PowerShell yang ditambahkan.

Menentukan fungsionalitas kelas dasar

Seperti yang dijelaskan dalam Merancang Penyedia Windows PowerShell Anda, kelas System.Management.Automation.Provider.NavigationCmdletProvider berasal dari beberapa kelas lain yang menyediakan fungsionalitas penyedia yang berbeda. Oleh karena itu, penyedia konten Windows PowerShell biasanya mendefinisikan semua fungsionalitas yang disediakan oleh kelas tersebut.

Untuk informasi selengkapnya tentang cara menerapkan fungsionalitas untuk menambahkan informasi inisialisasi khusus sesi dan untuk melepaskan sumber daya yang digunakan oleh penyedia, lihat Membuat Penyedia Windows PowerShell Dasar. Namun, sebagian besar penyedia, termasuk penyedia yang dijelaskan di sini, dapat menggunakan implementasi default fungsionalitas ini yang disediakan oleh Windows PowerShell.

Untuk mengakses penyimpanan data, penyedia harus mengimplementasikan metode kelas dasar System.Management.Automation.Provider.DriveCmdletProvider . Untuk informasi selengkapnya tentang menerapkan metode ini, lihat Membuat Penyedia Drive Windows PowerShell.

Untuk memanipulasi item penyimpanan data, seperti mendapatkan, mengatur, dan menghapus item, penyedia harus menerapkan metode yang disediakan oleh kelas dasar System.Management.Automation.Provider.ItemCmdletProvider . Untuk informasi selengkapnya tentang menerapkan metode ini, lihat Membuat Penyedia Item Windows PowerShell.

Untuk bekerja pada penyimpanan data multi-lapis, penyedia harus menerapkan metode yang disediakan oleh kelas dasar System.Management.Automation.Provider.ContainerCmdletProvider . Untuk informasi selengkapnya tentang menerapkan metode ini, lihat Membuat Penyedia Kontainer Windows PowerShell.

Untuk mendukung perintah rekursif, kontainer berlapis, dan jalur relatif, penyedia harus mengimplementasikan kelas dasar System.Management.Automation.Provider.NavigationCmdletProvider . Selain itu, penyedia konten Windows PowerShell ini dapat melampirkan antarmuka System.Management.Automation.Provider.IContentCmdletProvider ke kelas dasar System.Management.Automation.Provider.NavigationCmdletProvider , dan oleh karena itu harus mengimplementasikan metode yang disediakan oleh kelas tersebut. Untuk informasi selengkapnya, lihat menerapkan metode tersebut, lihat Menerapkan Navigasi Penyedia Windows PowerShell.

Menerapkan Pembaca Konten

Untuk membaca konten dari item, penyedia harus mengimplementasikan kelas pembaca konten yang berasal dari System.Management.Automation.Provider.IContentReader. Pembaca konten untuk penyedia ini memungkinkan akses ke konten baris dalam tabel data. Kelas pembaca konten menentukan metode Baca yang mengambil data dari baris yang ditunjukkan dan mengembalikan daftar yang mewakili data tersebut, metode Cari yang memindahkan pembaca konten, metode Tutup yang menutup pembaca konten, dan metode Disposisi .

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

Menerapkan Penulis Konten

Untuk menulis konten ke item, penyedia harus mengimplementasikan kelas penulis konten yang berasal dari System.Management.Automation.Provider.IContentWriter. Kelas penulis konten mendefinisikan metode Write yang menulis konten baris yang ditentukan, metode Seek yang memindahkan penulis konten, metode Close yang menutup penulis konten, dan metode 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

Mengambil Pembaca Konten

Untuk mendapatkan konten dari item, penyedia harus mengimplementasikan System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader* untuk mendukung Get-Content cmdlet. Metode ini mengembalikan pembaca konten untuk item yang terletak di jalur yang ditentukan. Objek pembaca kemudian dapat dibuka untuk membaca konten.

Berikut adalah implementasi System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader* untuk metode ini untuk penyedia ini.

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

Hal yang Perlu Diingat Tentang Menerapkan GetContentReader

Kondisi berikut mungkin berlaku untuk implementasi System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader*:

Melampirkan Parameter Dinamis ke Cmdlet Get-Content

Get-Content Cmdlet mungkin memerlukan parameter tambahan yang ditentukan secara dinamis pada runtime. Untuk menyediakan parameter dinamis ini, penyedia konten Windows PowerShell harus mengimplementasikan metode System.Management.Automation.Provider.IContentCmdletProvider.GetContentReaderdynamicparameters*. Metode ini mengambil parameter dinamis untuk item di jalur yang ditunjukkan dan mengembalikan objek yang memiliki properti dan bidang dengan atribut penguraian yang mirip dengan kelas cmdlet atau objek System.Management.Automation.RuntimeDefinedParameterDictionary . Runtime Windows PowerShell menggunakan objek yang dikembalikan untuk menambahkan parameter ke cmdlet.

Penyedia kontainer Windows PowerShell ini tidak mengimplementasikan metode ini. Namun, kode berikut adalah implementasi default dari metode ini.

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

Mengambil Penulis Konten

Untuk menulis konten ke item, penyedia harus mengimplementasikan System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter* untuk mendukung Set-Content cmdlet dan.Add-Content Metode ini mengembalikan penulis konten untuk item yang terletak di jalur yang ditentukan.

Berikut adalah implementasi System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter* untuk metode ini.

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);
}

Hal yang Perlu Diingat Tentang Menerapkan GetContentWriter

Ketentuan berikut mungkin berlaku untuk implementasi System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter*:

Melampirkan Parameter Dinamis ke Cmdlet Add-Content dan Set-Content

Cmdlet Add-Content dan Set-Content mungkin memerlukan parameter dinamis tambahan yang ditambahkan runtime. Untuk menyediakan parameter dinamis ini, penyedia konten Windows PowerShell harus mengimplementasikan metode System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriterDynamicParameters* untuk menangani parameter ini. Metode ini mengambil parameter dinamis untuk item di jalur yang ditunjukkan dan mengembalikan objek yang memiliki properti dan bidang dengan atribut penguraian yang mirip dengan kelas cmdlet atau objek System.Management.Automation.RuntimeDefinedParameterDictionary . Runtime Windows PowerShell menggunakan objek yang dikembalikan untuk menambahkan parameter ke cmdlet.

Penyedia kontainer Windows PowerShell ini tidak mengimplementasikan metode ini. Namun, kode berikut adalah implementasi default dari metode ini.

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

Menghapus Konten

Penyedia konten Anda mengimplementasikan metode System.Management.Automation.Provider.IContentCmdletProvider.ClearContent* untuk mendukung Clear-Content cmdlet. Metode ini menghapus konten item di jalur yang ditentukan, tetapi membiarkan item tetap utuh.

Berikut adalah implementasi metode System.Management.Automation.Provider.IContentCmdletProvider.ClearContent* untuk penyedia ini.

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

Hal yang Perlu Diingat Tentang Menerapkan ClearContent

Ketentuan berikut mungkin berlaku untuk implementasi System.Management.Automation.Provider.IContentCmdletProvider.ClearContent*:

Melampirkan Parameter Dinamis ke Cmdlet Clear-Content

Clear-Content Cmdlet mungkin memerlukan parameter dinamis tambahan yang ditambahkan saat runtime. Untuk menyediakan parameter dinamis ini, penyedia konten Windows PowerShell harus mengimplementasikan metode System.Management.Automation.Provider.IContentCmdletProvider.ClearContentDynamicParameters* untuk menangani parameter ini. Metode ini mengambil parameter untuk item di jalur yang ditunjukkan. Metode ini mengambil parameter dinamis untuk item di jalur yang ditunjukkan dan mengembalikan objek yang memiliki properti dan bidang dengan atribut penguraian yang mirip dengan kelas cmdlet atau objek System.Management.Automation.RuntimeDefinedParameterDictionary . Runtime Windows PowerShell menggunakan objek yang dikembalikan untuk menambahkan parameter ke cmdlet.

Penyedia kontainer Windows PowerShell ini tidak mengimplementasikan metode ini. Namun, kode berikut adalah implementasi default dari metode ini.

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

Sampel Kode

Untuk kode sampel lengkap, lihat Sampel Kode AccessDbProviderSample06.

Menentukan Jenis Objek dan Pemformatan

Saat menulis penyedia, mungkin perlu menambahkan anggota ke objek yang ada atau menentukan objek baru. Setelah ini selesai, Anda harus membuat file Jenis yang dapat digunakan Windows PowerShell untuk mengidentifikasi anggota objek dan file Format yang menentukan bagaimana objek ditampilkan. Untuk informasi selengkapnya, lihat Memperluas Jenis dan Pemformatan Objek.

Membangun Penyedia Windows PowerShell

Lihat Cara mendaftarkan cmdlet, penyedia, dan aplikasi host.

Menguji Penyedia Windows PowerShell

Ketika penyedia Windows PowerShell Anda telah terdaftar dengan Windows PowerShell, Anda dapat mengujinya dengan menjalankan cmdlet yang didukung pada baris perintah. Misalnya, uji penyedia konten sampel.

Gunakan Get-Content cmdlet untuk mengambil konten item yang ditentukan dalam tabel database pada jalur yang ditentukan oleh Path parameter. Parameter menentukan ReadCount jumlah item untuk dibaca oleh pembaca konten yang ditentukan (default 1). Dengan entri perintah berikut, cmdlet mengambil dua baris (item) dari tabel dan menampilkan isinya. Perhatikan bahwa contoh output berikut menggunakan database Access fiktif.

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

Lihat Juga

Membuat penyedia Windows PowerShell

Rancang Penyedia Windows PowerShell Anda

Memperluas Jenis Objek dan Pemformatan

Menerapkan penyedia Windows PowerShell Navigasi

Cara Mendaftarkan Cmdlet, Penyedia, dan Aplikasi Host

Windows PowerShell SDK

Panduan Pemrogram Windows PowerShell