Delen via


Het creëren van een Windows PowerShell Content Provider

Dit onderwerp beschrijft hoe je een Windows PowerShell-provider kunt maken waarmee de gebruiker de inhoud van de items in een datastore kan manipuleren. Als gevolg hiervan wordt een provider die de inhoud van items kan manipuleren een Windows PowerShell-contentprovider genoemd.

Opmerking

Je kunt het C#-bronbestand (AccessDBSampleProvider06.cs) van deze provider downloaden met behulp van de Microsoft Windows Software Development Kit voor Windows Vista en .NET Framework 3.0 Runtime Components. Voor downloadinstructies, zie Hoe installeer je Windows PowerShell en download de Windows PowerShell SDK. De gedownloade bronbestanden zijn beschikbaar in de <PowerShell Samples-map> . Voor meer informatie over andere implementaties van Windows PowerShell-providers, zie Designing Your Windows PowerShell Provider.

Definieer de Windows PowerShell Content Provider Class

Een Windows PowerShell-contentprovider moet een .NET-klasse aanmaken die de System.Management.Automation.Provider.IContentCmdletProvider-interface ondersteunt. Hier is de klassedefinitie voor de itemleverancier die in deze sectie wordt beschreven.

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

Let op dat in deze klassedefinitie het attribuut System.Management.Automation.Provider.CmdletProviderAttribute twee parameters bevat. De eerste parameter specificeert een gebruiksvriendelijke naam voor de provider die door Windows PowerShell wordt gebruikt. De tweede parameter specificeert de Windows PowerShell-specifieke mogelijkheden die de provider tijdens de commandoverwerking aan de Windows PowerShell-runtime blootstelt. Voor deze provider zijn er geen extra Windows PowerShell-specifieke mogelijkheden.

Definieer functionaliteit van de basisklasse

Zoals beschreven in Design Your Windows PowerShell Provider, is de klasse System.Management.Automation.Provider.NavigationCmdletProvider afgeleid van verschillende andere klassen die verschillende providerfunctionaliteit boden. Een Windows PowerShell-contentprovider definieert daarom doorgaans alle functionaliteit die door deze klassen wordt geleverd.

Voor meer informatie over hoe functionaliteit te implementeren voor het toevoegen van sessie-specifieke initialisatie-informatie en het vrijgeven van resources die door de provider worden gebruikt, zie Een Basis Windows PowerShell Provider aanmaken. De meeste providers, inclusief de hier beschreven provider, kunnen echter de standaardimplementatie van deze functionaliteit gebruiken die door Windows PowerShell wordt geleverd.

Om toegang te krijgen tot de datastore moet de provider de methoden van de System.Management.Automation.Provider.DriveCmdletProvider-basisklasse implementeren. Voor meer informatie over het implementeren van deze methoden, zie Het aanmaken van een Windows PowerShell Drive Provider.

Om de items van een datawinkel te manipuleren, zoals het ophalen, instellen en wissen van items, moet de provider de methoden implementeren die worden geleverd door de System.Management.Automation.Provider.ItemCmdletProvider-basisklasse . Voor meer informatie over het implementeren van deze methoden, zie Het aanmaken van een Windows PowerShell Item Provider.

Om te werken aan meerlagige datastores moet de provider de methoden implementeren die worden geleverd door de basisklasse System.Management.Automation.Provider.ContainerCmdletProvider . Voor meer informatie over het implementeren van deze methoden, zie Het aanmaken van een Windows PowerShell Container Provider.

Om recursieve commando's, geneste containers en relatieve paden te ondersteunen, moet de provider de System.Management.Automation.Provider.NavigationCmdletProvider-basisklasse implementeren. Daarnaast kan deze Windows PowerShell-contentprovider System.Management.Automation.Provider.IContentCmdletProvider-interface koppelen aan de System.Management.Automation.Provider.NavigationCmdletProvider-basisklasse , en moet daarom de methoden implementeren die door die klasse worden aangeboden. Voor meer informatie, zie het implementeren van die methoden, zie Implement a Navigation Windows PowerShell Provider.

Implementatie van een Content Reader

Om inhoud van een item te lezen, moet een aanbieder een content reader-klasse implementeren die is afgeleid van System.Management.Automation.Provider.IContentReader. De inhoudslezer voor deze provider geeft toegang tot de inhoud van een rij in een datatabel. De content reader-klasse definieert een Read-methode die de data uit de aangegeven rij ophaalt en een lijst teruggeeft die die data vertegenwoordigt, een Seek-methode die de contentreader verplaatst, een Close-methode die de contentreader sluit, en een Dispose-methode .

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

Een Content Writer inzetten

Om content te schrijven bij een item, moet een provider een content writer-klasse implementeren die is afgeleid van System.Management.Automation.Provider.IContentWriter. De content writer-klasse definieert een Write-methode die de gespecificeerde rij-inhoud schrijft, een Seek-methode die de content writer verplaatst, een Close-methode die de content writer afsluit, en een Dispose-methode .

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

Het ophalen van de Content Reader

Om content van een item te verkrijgen, moet de provider de System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader* implementeren om de Get-Content cmdlet te ondersteunen. Deze methode geeft de inhoudslezer terug voor het item dat zich op het opgegeven pad bevindt. Het lezerobject kan vervolgens worden geopend om de inhoud te lezen.

Hier is de implementatie van System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader* voor deze methode voor deze provider.

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

Dingen om te onthouden bij het implementeren van GetContentReader

De volgende voorwaarden kunnen van toepassing zijn op een implementatie van System.Management.Automation.Provider.IContentCmdletProvider.GetContentReader*:

Dynamische parameters toevoegen aan de Get-Content cmdlet

De Get-Content cmdlet kan extra parameters vereisen die dynamisch worden gespecificeerd tijdens runtime. Om deze dynamische parameters te bieden, moet de Windows PowerShell-contentprovider de System.Management.Automation.Provider.IContentCmdletProvider.GetContentReaderdynamicparameters* implementeren. Deze methode haalt dynamische parameters op voor het item op het aangegeven pad en geeft een object terug dat eigenschappen en velden heeft met parsingattributen vergelijkbaar met een cmdlet-klasse of een System.Management.Automation.RuntimeDefinedParameterDictionary-object . De Windows PowerShell-runtime gebruikt het geretourneerde object om de parameters aan de cmdlet toe te voegen.

Deze Windows PowerShell-containerprovider implementeert deze methode niet. De volgende code is echter de standaardimplementatie van deze methode.

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

De Content Writer ophalen

Om inhoud naar een item te schrijven, moet de provider de System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter* implementeren om de en Add-Content cmdlets Set-Content te ondersteunen. Deze methode geeft de content writer terug voor het item dat zich op het opgegeven pad bevindt.

Hier is de implementatie van System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter* voor deze methode.

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

Dingen om te onthouden bij het implementeren van GetContentWriter

De volgende voorwaarden kunnen van toepassing zijn op uw implementatie van System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriter*:

Dynamische parameters koppelen aan de Add-Content en Set-Content cmdlets

De en Set-Content cmdlets Add-Content kunnen extra dynamische parameters vereisen die aan de runtime worden toegevoegd. Om deze dynamische parameters te bieden, moet de Windows PowerShell-contentprovider de System.Management.Automation.Provider.IContentCmdletProvider.GetContentWriterDynamicParameters* implementeren om deze parameters te verwerken. Deze methode haalt dynamische parameters op voor het item op het aangegeven pad en geeft een object terug dat eigenschappen en velden heeft met parsingattributen vergelijkbaar met een cmdlet-klasse of een System.Management.Automation.RuntimeDefinedParameterDictionary-object . De Windows PowerShell-runtime gebruikt het teruggegeven object om de parameters aan de cmdlets toe te voegen.

Deze Windows PowerShell-containerprovider implementeert deze methode niet. De volgende code is echter de standaardimplementatie van deze methode.

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

Content uitwissen

Uw contentprovider implementeert de System.Management.Automation.Provider.IContentCmdletProvider.ClearContent* -methode ter ondersteuning van de Clear-Content cmdlet. Deze methode verwijdert de inhoud van het item op het opgegeven pad, maar laat het item intact.

Hier is de implementatie van de System.Management.Automation.Provider.IContentCmdletProvider.ClearContent*- methode voor deze provider.

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

Dingen om te onthouden bij het implementeren van ClearContent

De volgende voorwaarden kunnen van toepassing zijn op een implementatie van System.Management.Automation.Provider.IContentCmdletProvider.ClearContent*:

Dynamische parameters toevoegen aan de Clear-Content cmdlet

De Clear-Content cmdlet kan extra dynamische parameters vereisen die tijdens runtime worden toegevoegd. Om deze dynamische parameters te bieden, moet de Windows PowerShell-contentprovider de methode System.Management.Automation.Provider.IContentCmdletProvider.ClearContentDynamicParameters* implementeren om deze parameters te verwerken. Deze methode haalt de parameters op voor het item op het aangegeven pad. Deze methode haalt dynamische parameters op voor het item op het aangegeven pad en geeft een object terug dat eigenschappen en velden heeft met parsingattributen vergelijkbaar met een cmdlet-klasse of een System.Management.Automation.RuntimeDefinedParameterDictionary-object . De Windows PowerShell-runtime gebruikt het geretourneerde object om de parameters aan de cmdlet toe te voegen.

Deze Windows PowerShell-containerprovider implementeert deze methode niet. De volgende code is echter de standaardimplementatie van deze methode.

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

Codevoorbeeld

Voor volledige voorbeeldcode, zie AccessDbProviderSample06 Codevoorbeeld.

Objecttypes en opmaak definiëren

Bij het schrijven van een provider kan het nodig zijn leden toe te voegen aan bestaande objecten of nieuwe objecten te definiëren. Wanneer dit is gedaan, moet je een Types-bestand aanmaken dat Windows PowerShell kan gebruiken om de leden van het object te identificeren en een Format-bestand dat definieert hoe het object wordt weergegeven. Voor meer informatie, zie Uitbreiden van Objecttypes en Opmaak.

De Windows PowerShell Provider bouwen

Bekijk hoe u cmdlets, providers en hostapplicaties registreert.

Het testen van de Windows PowerShell Provider

Wanneer je Windows PowerShell-provider geregistreerd is bij Windows PowerShell, kun je dit testen door de ondersteunde cmdlets op de commandoregel uit te voeren. Test bijvoorbeeld de voorbeeldcontentprovider.

Gebruik de Get-Content cmdlet om de inhoud van het opgegeven item in de databasetabel op te halen op het pad dat door de Path parameter is gespecificeerd. De ReadCount parameter specificeert het aantal items dat de gedefinieerde inhoudslezer moet lezen (standaard 1). Met de volgende commandovermelding haalt de cmdlet twee rijen (items) uit de tabel en toont de inhoud ervan. Let op dat de volgende voorbeeldoutput een fictieve Access-database gebruikt.

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

Zie ook

Het aanmaken van Windows PowerShell-providers

Design Your Windows PowerShell provider

Uitbreiden van objecttypes en opmaak

Implementeer een Navigatie Windows PowerShell-provider

Hoe registreer je cmdlets, providers en hostapplicaties

Windows PowerShell SDK

Windows PowerShell Programmeursgids