Skapa en Windows PowerShell-innehållsprovider

Det här avsnittet beskriver hur du skapar en Windows PowerShell-provider som gör att användaren kan ändra innehållet i objekten i ett datalager. Därför kallas en leverantör som kan manipulera innehållet i objekt som en Windows PowerShell innehållsleverantör.

Anteckning

Du kan ladda ned C#-källfilen (AccessDBSampleProvider06.cs) för den här providern med hjälp av Microsoft Windows Software Development Kit för Windows Vista och .NET Framework 3.0 Runtime Components. Anvisningar för nedladdning finns i Installera Windows PowerShell och Ladda ned Windows PowerShell SDK. De nedladdade källfilerna är tillgängliga i <PowerShell Samples> katalogen . Mer information om andra Windows PowerShell-providerimplementering finns i Designing Your Windows PowerShell Provider (Utforma din Windows PowerShell provider).

Definiera Windows PowerShell innehållsproviderklass

En Windows PowerShell måste skapa en .NET-klass som stöder gränssnittet System.Management.Automation.Provider.Icontentcmdletprovider. Här är klassdefinitionen för objektprovidern som beskrivs i det här avsnittet.

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

Observera att i den här klassdefinitionen innehåller attributet System.Management.Automation.Provider.Cmdletproviderattribute två parametrar. Den första parametern anger ett användarvänligt namn för providern som används av Windows PowerShell. Den andra parametern anger Windows PowerShell specifika funktioner som providern exponerar för Windows PowerShell under kommandobearbetningen. För den här providern finns det inga Windows PowerShell specifika funktioner.

Definiera funktioner i basklassen

Enligt beskrivningen i Design Your Windows PowerShell Providerhärleds klassen System.Management.Automation.Provider.Navigationcmdletprovider från flera andra klasser som tillhandahöll olika providerfunktioner. En Windows PowerShell innehållsprovider definierar därför vanligtvis alla funktioner som tillhandahålls av dessa klasser.

Mer information om hur du implementerar funktioner för att lägga till sessionsspecifik initieringsinformation och för att frigöra resurser som används av providern finns i Skapa en grundläggande Windows PowerShell provider. De flesta leverantörer, inklusive providern som beskrivs här, kan dock använda standardimplementering av den här funktionen som tillhandahålls av Windows PowerShell.

För att få åtkomst till datalagret måste providern implementera metoderna för basklassen System.Management.Automation.Provider.Drivecmdletprovider. Mer information om hur du implementerar dessa metoder finns i Skapa en Windows PowerShell-enhetsprovider.

Om du vill ändra objekten i ett datalager, till exempel hämta, ange och rensa objekt, måste providern implementera de metoder som tillhandahålls av basklassen System.Management.Automation.Provider.Itemcmdletprovider. Mer information om hur du implementerar dessa metoder finns i Skapa en Windows PowerShell objektprovider.

Om du vill arbeta med datalager med flera lager måste providern implementera de metoder som tillhandahålls av basklassen System.Management.Automation.Provider.Containercmdletprovider. Mer information om hur du implementerar dessa metoder finns i Skapa en Windows PowerShell containerprovider.

För att stödja rekursiva kommandon, kapslade containrar och relativa sökvägar måste providern implementera basklassen System.Management.Automation.Provider.Navigationcmdletprovider. Dessutom kan den här Windows PowerShell-innehållsprovidern bifogar gränssnittet System.Management.Automation.Provider.Icontentcmdletprovider till basklassen System.Management.Automation.Provider.Navigationcmdletprovider och måste därför implementera de metoder som tillhandahålls av den klassen. Mer information finns i Implementera dessa metoder i Implementera en Windows PowerShell navigeringsprovider.

Implementera en innehållsläsare

Om du vill läsa innehåll från ett objekt måste en provider implementera en innehållsläsarklass som härleds från System.Management.Automation.Provider.Icontentreader. Innehållsläsaren för den här providern ger åtkomst till innehållet på en rad i en datatabell. Klassen innehållsläsare definierar en Läs-metod som hämtar data från den angivna raden och returnerar en lista som representerar dessa data, en Sök-metod som flyttar innehållsläsaren, en Close-metod som stänger innehållsläsaren och en Avta-metod.

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

Implementera en innehållsskrivare

Om du vill skriva innehåll till ett objekt måste en provider implementera en innehållsskrivarklass som härleds från System.Management.Automation.Provider.Icontentwriter. Klassen content writer definierar en Skriv-metod som skriver det angivna radinnehållet, en Sök-metod som flyttar innehållsskrivaren, en Close-metod som stänger innehållsskrivaren och en flyttningsmetod.

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

Hämta innehållsläsaren

Om du vill hämta innehåll från ett objekt måste providern implementera System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader* för att stödja Get-Content cmdleten. Den här metoden returnerar innehållsläsaren för objektet som finns på den angivna sökvägen. Läsarobjektet kan sedan öppnas för att läsa innehållet.

Här är implementeringen av System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader* för den här metoden för den här providern.

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

Saker att komma ihåg om att implementera GetContentReader

Följande villkor kan gälla för en implementering av System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader*:

Koppla dynamiska parametrar till Get-Content cmdlet

Get-ContentCmdleten kan kräva ytterligare parametrar som anges dynamiskt vid körning. För att tillhandahålla dessa dynamiska parametrar måste Windows PowerShell-innehållsprovidern implementera metoden System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreaderdynamicparameters*. Den här metoden hämtar dynamiska parametrar för objektet på den angivna sökvägen och returnerar ett objekt som har egenskaper och fält med parsningsattribut som liknar en cmdlet-klass eller ett System.Management.Automation.Runtimedefinedparameterdictionary-objekt. Den Windows PowerShell körningen använder det returnerade objektet för att lägga till parametrarna i cmdleten.

Den Windows PowerShell containerprovidern implementerar inte den här metoden. Följande kod är dock standardimplementering av den här metoden.

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

Hämta innehållsskrivaren

Om du vill skriva innehåll till ett objekt måste providern implementera System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter* för att stödja Set-Content Add-Content cmdletarna och . Den här metoden returnerar innehållsskrivaren för objektet som finns på den angivna sökvägen.

Här är implementeringen av System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter* för den här metoden.

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

Saker att komma ihåg om att implementera GetContentWriter

Följande villkor kan gälla för din implementering av System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter*:

Koppla dynamiska parametrar till Add-Content och Set-Content cmdlets

Cmdletarna och Add-Content kan kräva ytterligare dynamiska parametrar som läggs till i en Set-Content körning. För att kunna tillhandahålla dessa dynamiska parametrar måste Windows PowerShell-innehållsprovidern implementera metoden System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriterdynamicparameters* för att hantera dessa parametrar. Den här metoden hämtar dynamiska parametrar för objektet på den angivna sökvägen och returnerar ett objekt som har egenskaper och fält med parsningsattribut som liknar en cmdlet-klass eller ett System.Management.Automation.Runtimedefinedparameterdictionary-objekt. Den Windows PowerShell körningen använder det returnerade objektet för att lägga till parametrarna i cmdletarna.

Den Windows PowerShell containerprovidern implementerar inte den här metoden. Följande kod är dock standardimplementering av den här metoden.

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

Rensa innehåll

Innehållsleverantören implementerar metoden System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent* som stöd för Clear-Content cmdleten . Den här metoden tar bort innehållet i objektet på den angivna sökvägen, men lämnar objektet intakt.

Här är implementeringen av metoden System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent* för den här providern.

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

Saker att komma ihåg om att implementera ClearContent

Följande villkor kan gälla för en implementering av System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*:

Koppla dynamiska parametrar till Clear-Content cmdlet

Clear-ContentCmdleten kan kräva ytterligare dynamiska parametrar som läggs till vid körning. För att tillhandahålla dessa dynamiska parametrar måste Windows PowerShell-innehållsprovidern implementera metoden System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontentdynamicparameters* för att hantera dessa parametrar. Den här metoden hämtar parametrarna för objektet på den angivna sökvägen. Den här metoden hämtar dynamiska parametrar för objektet på den angivna sökvägen och returnerar ett objekt som har egenskaper och fält med parsningsattribut som liknar en cmdlet-klass eller ett System.Management.Automation.Runtimedefinedparameterdictionary-objekt. Den Windows PowerShell körningen använder det returnerade objektet för att lägga till parametrarna i cmdleten.

Den Windows PowerShell containerprovidern implementerar inte den här metoden. Följande kod är dock standardimplementering av den här metoden.

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

Kodexempel

Fullständig exempelkod finns i AccessDbProviderSample06 Code Sample.

Definiera objekttyper och formatering

När du skriver en provider kan det vara nödvändigt att lägga till medlemmar i befintliga objekt eller definiera nya objekt. När detta är klart måste du skapa en Types-fil som Windows PowerShell kan använda för att identifiera medlemmarna i objektet och en Format-fil som definierar hur objektet visas. Mer information finns i Utöka objekttyper och formatera.

Skapa Windows PowerShell providern

Se Registrera cmdlets, providers och värdprogram.

Testa Windows PowerShell providern

När din Windows PowerShell har registrerats med Windows PowerShell kan du testa den genom att köra de cmdlets som stöds på kommandoraden. Testa till exempel innehållsprovidern.

Använd Get-Content cmdleten för att hämta innehållet i det angivna objektet i databastabellen på den sökväg som anges av Path parametern . Parametern ReadCount anger antalet objekt som den definierade innehållsläsaren ska läsa (standard 1). Med följande kommandopost hämtar cmdleten två rader (objekt) från tabellen och visar deras innehåll. Observera att följande exempelutdata använder en fiktiv Access-databas.

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

Se även

Skapa Windows PowerShell leverantörer

Utforma din Windows PowerShell provider

Utöka objekttyper och formatering

Implementera en leverantör Windows PowerShell navigeringsfält

Registrera cmdlets, providers och värdprogram

Windows PowerShell SDK

Programmeringsguide för Windows PowerShell