Partager via


Créer un fournisseur de contenu Windows PowerShell

Ce sujet décrit comment créer un fournisseur Windows PowerShell permettant à l’utilisateur de manipuler le contenu des éléments dans un magasin de données. Par conséquent, un fournisseur capable de manipuler le contenu des éléments est appelé fournisseur de contenu Windows PowerShell.

Note

Vous pouvez télécharger le fichier source C# (AccessDBSampleProvider06.cs) de ce fournisseur en utilisant le Microsoft Windows Software Development Kit pour Windows Vista et les composants d’exécution .NET Framework 3.0. Pour les instructions de téléchargement, consultez Comment installer Windows PowerShell et télécharger le SDK Windows PowerShell. Les fichiers sources téléchargés sont disponibles dans le <répertoire PowerShell Samples> . Pour plus d’informations sur les autres implémentations de fournisseurs Windows PowerShell, voir Designing Your Windows PowerShell Provider.

Définir la classe fournisseur de contenu Windows PowerShell

Un fournisseur de contenu PowerShell Windows doit créer une classe .NET qui prend en charge l’interface System.Management.Automation.Provider.IContentCmdletProvider . Voici la définition de classe du fournisseur d’items décrit dans cette section.

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

Notez que dans cette définition de classe, l’attribut System.Management.Automation.Provider.CmdletProviderAttribute inclut deux paramètres. Le premier paramètre spécifie un nom convivial pour le fournisseur utilisé par Windows PowerShell. Le second paramètre spécifie les capacités spécifiques à Windows PowerShell que le fournisseur expose à l’exécution Windows PowerShell lors du traitement des commandes. Pour ce fournisseur, il n’y a pas de fonctionnalités spécifiques à Windows PowerShell supplémentaires.

Définir la fonctionnalité de la classe de base

Comme décrit dans Design Your Windows PowerShell Provider, la classe System.Management.Automation.Provider.NavigationCmdletProvider dérive de plusieurs autres classes qui offraient différentes fonctionnalités de fournisseurs. Un fournisseur de contenu Windows PowerShell définit donc généralement toutes les fonctionnalités fournies par ces classes.

Pour plus d’informations sur la manière d’implémenter des fonctionnalités permettant d’ajouter des informations d’initialisation spécifiques à chaque session et de la publication des ressources utilisées par le fournisseur, voir Créer un fournisseur PowerShell Windows de base. Cependant, la plupart des fournisseurs, y compris celui décrit ici, peuvent utiliser l’implémentation par défaut de cette fonctionnalité fournie par Windows PowerShell.

Pour accéder au magasin de données, le fournisseur doit implémenter les méthodes de la classe de base System.Management.Automation.Provider.DriveCmdletProvider . Pour plus d’informations sur la mise en œuvre de ces méthodes, voir Créer un fournisseur de disques Windows PowerShell.

Pour manipuler les éléments d’un magasin de données, tels que l’obtention, la mise en place et la compensation des éléments, le fournisseur doit implémenter les méthodes fournies par la classe de base System.Management.Automation.Provider.ItemCmdletProvider . Pour plus d’informations sur la mise en œuvre de ces méthodes, voir Créer un fournisseur d’éléments PowerShell Windows.

Pour travailler sur des magasins de données multi-couches, le fournisseur doit implémenter les méthodes fournies par la classe de base System.Management.Automation.Provider.ContainerCmdletProvider . Pour plus d’informations sur la mise en œuvre de ces méthodes, voir Créer un fournisseur de conteneurs Windows PowerShell.

Pour prendre en charge les commandes récursives, les conteneurs imbriqués et les chemins relatifs, le fournisseur doit implémenter la classe de base System.Management.Automation.Provider.NavigationCmdletProvider . De plus, ce fournisseur de contenu Windows PowerShell peut associer l’interface System.Management.Automation.Provider.IContentCmdletProvider à la classe base System.Management.Automation.Provider.NavigationCmdletProvider , et doit donc implémenter les méthodes fournies par cette classe. Pour plus d’informations, voir implémenter ces méthodes, voir Implémenter un fournisseur PowerShell Windows pour la navigation.

Implémentation d’un lecteur de contenu

Pour lire du contenu d’un article, un fournisseur doit implémenter une classe lecteur de contenu dérivée de System.Management.Automation.Provider.IContentReader. Le lecteur de contenu de ce fournisseur permet d’accéder au contenu d’une ligne dans une table de données. La classe lecteur de contenu définit une méthode Read qui récupère les données de la ligne indiquée et renvoie une liste représentant ces données, une méthode Seek qui déplace le lecteur de contenu, une méthode Close qui ferme le lecteur de contenu, et une méthode 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

Mettre en place un rédacteur de contenu

Pour écrire du contenu sur un élément, un fournisseur doit implémenter une classe de rédacteur de contenu dérivée de System.Management.Automation.Provider.IContentWriter. La classe rédacteur de contenu définit une méthode Write qui écrit le contenu de la ligne spécifiée, une méthode Seek qui déplace le rédacteur de contenu, une méthode Close qui ferme le rédacteur de contenu, et une méthode Dispos .

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

Récupérer le lecteur de contenu

Pour obtenir du contenu à partir d’un élément, le fournisseur doit implémenter le System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader* pour supporter le Get-Content cmdlet. Cette méthode renvoie le lecteur de contenu de l’élément situé sur le chemin spécifié. L’objet lecteur peut alors être ouvert pour lire le contenu.

Voici l’implémentation de System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader* pour cette méthode et ce fournisseur.

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

Choses à retenir concernant la mise en œuvre de GetContentReader

Les conditions suivantes peuvent s’appliquer à une implémentation de System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader* :

Attacher des paramètres dynamiques au Get-Content cmdlet

Le Get-Content cmdlet peut nécessiter des paramètres supplémentaires spécifiés dynamiquement à l’exécution. Pour fournir ces paramètres dynamiques, le fournisseur de contenu PowerShell Windows doit implémenter la méthode System.Management.Automation.Provider.IContentCmdletProvider.GetContentReaderdynamicparameters* . Cette méthode récupère les paramètres dynamiques de l’élément sur le chemin indiqué et renvoie un objet ayant des propriétés et des champs avec des attributs d’analyse similaires à une classe cmdlet ou à un objet System.Management.Automation.RuntimeDefinedParameterDictionary . L’exécution PowerShell de Windows utilise l’objet retourné pour ajouter les paramètres au cmdlet.

Ce fournisseur de conteneurs Windows PowerShell n’implémente pas cette méthode. Cependant, le code suivant est l’implémentation par défaut de cette méthode.

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

Récupérer le rédacteur de contenu

Pour écrire du contenu sur un élément, le fournisseur doit implémenter le System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter* pour prendre en charge les Set-Content cmdlets et Add-Content . Cette méthode renvoie le rédacteur de contenu pour l’élément situé sur le chemin spécifié.

Voici l’implémentation de System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter* pour cette méthode.

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

Choses à retenir concernant la mise en œuvre de GetContentWriter

Les conditions suivantes peuvent s’appliquer à votre implémentation de System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter* :

Attacher les paramètres dynamiques aux commandlets Add-Content et Set-Content

Les Add-Content cmdlets et Set-Content peuvent nécessiter des paramètres dynamiques supplémentaires ajoutés à l’exécution. Pour fournir ces paramètres dynamiques, le fournisseur de contenu Windows PowerShell doit implémenter la méthode System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriterDynamicParameters* pour gérer ces paramètres. Cette méthode récupère les paramètres dynamiques de l’élément sur le chemin indiqué et renvoie un objet ayant des propriétés et des champs avec des attributs d’analyse similaires à une classe cmdlet ou à un objet System.Management.Automation.RuntimeDefinedParameterDictionary . L’exécution PowerShell de Windows utilise l’objet retourné pour ajouter les paramètres aux cmdlets.

Ce fournisseur de conteneurs Windows PowerShell n’implémente pas cette méthode. Cependant, le code suivant est l’implémentation par défaut de cette méthode.

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

Nettoyage du contenu

Votre fournisseur de contenu implémente la méthode System.Management.Automation.Provider.IContentCmdletProvider.ClearContent* en support du Clear-Content cmdlet. Cette méthode supprime le contenu de l’élément sur le chemin spécifié, mais laisse l’élément intact.

Voici la mise en œuvre de la méthode System.Management.Automation.Provider.IContentCmdletProvider.ClearContent* pour ce fournisseur.

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

Points à retenir concernant la mise en œuvre de ClearContent

Les conditions suivantes peuvent s’appliquer à une implémentation de System.Management.Automation.Provider.IContentCmdletProvider.ClearContent* :

Attacher des paramètres dynamiques au Clear-Content cmdlet

Le Clear-Content cmdlet peut nécessiter des paramètres dynamiques supplémentaires ajoutés à l’exécution. Pour fournir ces paramètres dynamiques, le fournisseur de contenu Windows PowerShell doit implémenter la méthode System.Management.Automation.Provider.IContentCmdletProvider.ClearContentDynamicParameters* pour gérer ces paramètres. Cette méthode récupère les paramètres de l’élément sur le chemin indiqué. Cette méthode récupère les paramètres dynamiques de l’élément sur le chemin indiqué et renvoie un objet ayant des propriétés et des champs avec des attributs d’analyse similaires à une classe cmdlet ou à un objet System.Management.Automation.RuntimeDefinedParameterDictionary . L’exécution PowerShell de Windows utilise l’objet retourné pour ajouter les paramètres au cmdlet.

Ce fournisseur de conteneurs Windows PowerShell n’implémente pas cette méthode. Cependant, le code suivant est l’implémentation par défaut de cette méthode.

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

Exemple de code

Pour un code d’exemple complet, voir AccessDbProviderSample06 Code Example.

Définition des types d’objets et mise en forme

Lors de l’écriture d’un fournisseur, il peut être nécessaire d’ajouter des membres à des objets existants ou de définir de nouveaux objets. Une fois cela fait, vous devez créer un fichier Types que Windows PowerShell peut utiliser pour identifier les membres de l’objet ainsi qu’un fichier Format qui définit la manière dont l’objet est affiché. Pour plus d’informations, voir Extension des types d’objets et de la mise en forme.

Construire le fournisseur Windows PowerShell

Voir comment enregistrer les commandants, les fournisseurs et les applications hôtes.

Test du fournisseur Windows PowerShell

Lorsque votre fournisseur Windows PowerShell est enregistré auprès de Windows PowerShell, vous pouvez le tester en exécutant les cmdlets supportés en ligne de commande. Par exemple, testez le fournisseur de contenu d’échantillon.

Utilisez le Get-Content cmdlet pour récupérer le contenu de l’élément spécifié dans la table de la base de données au chemin spécifié par le Path paramètre. Le ReadCount paramètre spécifie le nombre d’éléments que le lecteur de contenu défini doit lire (par défaut 1). À la saisie suivante de la commande, le cmdlet récupère deux lignes (items) de la table et affiche leur contenu. Notez que l’exemple suivant utilise une base de données Access fictive.

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

Voir aussi

Création de fournisseurs Windows PowerShell

Concevez votre fournisseur PowerShell Windows

Extension des types d’objets et de la mise en forme

Implémenter un fournisseur PowerShell de navigation Windows

Comment enregistrer des commandants, des fournisseurs et des applications hôtes

Windows PowerShell SDK

Guide du programmeur Windows PowerShell