Questa è una zona sorprendentemente complesso, ma ho un sacco di esperienza qui. In breve, ci sono alcuni cmdlet che accettano i percorsi win32 direttamente dalle API System.IO, e in genere usano un parametro -FilePath. Se si vuole scrivere un "powershelly" cmdlet ben educati, è necessario -Path e -LiteralPath, di accettare input da pipeline e lavorare con i percorsi di provider relativi e assoluti. Ecco un estratto da un post che ho scritto qualche tempo fa: [. In un primo momento]
percorsi in PowerShell sono difficili da capire PowerShell Paths - o PSPaths, da non confondere con i percorsi Win32 - nelle loro forme assolute, essi sono di due tipi distinti:
- Provider-qualificati:
FileSystem::c:\temp\foo.txt
- PSDrive qualificato:
c:\temp\foo.txt
E 'molto facile da ottenere confuso su fornitore-interna (Il ProviderPath
proprietà di un deliberato System.Management.Automation.PathInfo
- la parte a destra del ::
del percorso del provider qualificato sopra) e percorso di unità qualificati in quanto lo stesso aspetto se si guardano le unità provider predefinito FileSystem. Vale a dire, PSDrive ha lo stesso nome (C) del backing store nativo, il filesystem di Windows (C). Quindi, per rendere più facile per te per capire le differenze, crea un nuovo PSDrive:
ps c:\> new-psdrive temp filesystem c:\temp\
ps c:\> cd temp:
ps temp:\>
Ora, diamo un'occhiata a questo nuovo:
- Provider-qualificata:
FileSystem::c:\temp\foo.txt
- Drive- qualificata:
temp:\foo.txt
Un po 'più facile questa volta per vedere cosa c'è di diverso questa volta. Il testo in grassetto a destra del nome del provider è ProviderPath.
Quindi, i tuoi obiettivi per la scrittura di un cmdlet generalizzata fornitore-friendly (o funzioni avanzate) che accetta i percorsi sono:
- definire un parametro
LiteralPath
percorso alias di PSPath
- definire un parametro
Path
(che sarà risolvere i caratteri jolly/glob)
- assumere sempre si ricevono PSPaths, NON provider-percorsi nativo (ad esempio percorsi Win32)
Il punto numero tre è particolarmente importante. Inoltre, ovviamente LiteralPath
e Path
dovrebbero appartenere a set di parametri mutuamente esclusivi.
percorsi relativi
Una buona domanda è: come possiamo affrontare i percorsi relativi vengono passati a un cmdlet. Come si dovrebbe assumere tutti i percorsi di essere dato a sei PSPaths, diamo un'occhiata a ciò che il Cmdlet di seguito fa:
ps temp:\> write-zip -literalpath foo.txt
Il comando deve assumere foo.txt è l'unità corrente, quindi questo dovrebbe essere risolto immediatamente a ProcessRecord o EndProcessing blocco simile (utilizzando l'API di scripting qui per demo):
$provider = $null;
$drive = $null
$pathHelper = $ExecutionContext.SessionState.Path
$providerPath = $pathHelper.GetUnresolvedProviderPathFromPSPath(
"foo.txt", [ref]$provider, [ref]$drive)
Ora è tutto il necessario per ricreare le due forme assolute di PSPaths, e hai anche la ProviderPath assoluto nativo. Per creare un PSPath qualificato dal provider per foo.txt, utilizzare $provider.Name + “::” + $providerPath
. Se $drive
non è $null
(la posizione corrente potrebbe essere qualificata dal fornitore, nel qual caso $drive
sarà $null
), quindi utilizzare $drive.name + ":\" + $drive.CurrentLocation + "\" + "foo.txt"
per ottenere un PSPath qualificato per l'unità.
Quickstart C# scheletro
Ecco uno scheletro di un C# fornitore-aware cmdlet per farti andare. Ha incorporato controlli per assicurarsi che gli sia stato assegnato un percorso del provider FileSystem.Io sono nel processo di confezionamento questo per NuGet per aiutare gli altri ottenere la scrittura ben educati Cmdlet fornitore-aware:
using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using Microsoft.PowerShell.Commands;
namespace PSQuickStart
{
[Cmdlet(VerbsCommon.Get, Noun,
DefaultParameterSetName = ParamSetPath,
SupportsShouldProcess = true)
]
public class GetFileMetadataCommand : PSCmdlet
{
private const string Noun = "FileMetadata";
private const string ParamSetLiteral = "Literal";
private const string ParamSetPath = "Path";
private string[] _paths;
private bool _shouldExpandWildcards;
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = true,
ParameterSetName = ParamSetLiteral)
]
[Alias("PSPath")]
[ValidateNotNullOrEmpty]
public string[] LiteralPath
{
get { return _paths; }
set { _paths = value; }
}
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = ParamSetPath)
]
[ValidateNotNullOrEmpty]
public string[] Path
{
get { return _paths; }
set
{
_shouldExpandWildcards = true;
_paths = value;
}
}
protected override void ProcessRecord()
{
foreach (string path in _paths)
{
// This will hold information about the provider containing
// the items that this path string might resolve to.
ProviderInfo provider;
// This will be used by the method that processes literal paths
PSDriveInfo drive;
// this contains the paths to process for this iteration of the
// loop to resolve and optionally expand wildcards.
List<string> filePaths = new List<string>();
if (_shouldExpandWildcards)
{
// Turn *.txt into foo.txt,foo2.txt etc.
// if path is just "foo.txt," it will return unchanged.
filePaths.AddRange(this.GetResolvedProviderPathFromPSPath(path, out provider));
}
else
{
// no wildcards, so don't try to expand any * or ? symbols.
filePaths.Add(this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(
path, out provider, out drive));
}
// ensure that this path (or set of paths after wildcard expansion)
// is on the filesystem. A wildcard can never expand to span multiple
// providers.
if (IsFileSystemPath(provider, path) == false)
{
// no, so skip to next path in _paths.
continue;
}
// at this point, we have a list of paths on the filesystem.
foreach (string filePath in filePaths)
{
PSObject custom;
// If -whatif was supplied, do not perform the actions
// inside this "if" statement; only show the message.
//
// This block also supports the -confirm switch, where
// you will be asked if you want to perform the action
// "get metadata" on target: foo.txt
if (ShouldProcess(filePath, "Get Metadata"))
{
if (Directory.Exists(filePath))
{
custom = GetDirectoryCustomObject(new DirectoryInfo(filePath));
}
else
{
custom = GetFileCustomObject(new FileInfo(filePath));
}
WriteObject(custom);
}
}
}
}
private PSObject GetFileCustomObject(FileInfo file)
{
// this message will be shown if the -verbose switch is given
WriteVerbose("GetFileCustomObject " + file);
// create a custom object with a few properties
PSObject custom = new PSObject();
custom.Properties.Add(new PSNoteProperty("Size", file.Length));
custom.Properties.Add(new PSNoteProperty("Name", file.Name));
custom.Properties.Add(new PSNoteProperty("Extension", file.Extension));
return custom;
}
private PSObject GetDirectoryCustomObject(DirectoryInfo dir)
{
// this message will be shown if the -verbose switch is given
WriteVerbose("GetDirectoryCustomObject " + dir);
// create a custom object with a few properties
PSObject custom = new PSObject();
int files = dir.GetFiles().Length;
int subdirs = dir.GetDirectories().Length;
custom.Properties.Add(new PSNoteProperty("Files", files));
custom.Properties.Add(new PSNoteProperty("Subdirectories", subdirs));
custom.Properties.Add(new PSNoteProperty("Name", dir.Name));
return custom;
}
private bool IsFileSystemPath(ProviderInfo provider, string path)
{
bool isFileSystem = true;
// check that this provider is the filesystem
if (provider.ImplementingType != typeof(FileSystemProvider))
{
// create a .NET exception wrapping our error text
ArgumentException ex = new ArgumentException(path +
" does not resolve to a path on the FileSystem provider.");
// wrap this in a powershell errorrecord
ErrorRecord error = new ErrorRecord(ex, "InvalidProvider",
ErrorCategory.InvalidArgument, path);
// write a non-terminating error to pipeline
this.WriteError(error);
// tell our caller that the item was not on the filesystem
isFileSystem = false;
}
return isFileSystem;
}
}
}
linee guida di sviluppo cmdlet (Microsoft)
Ecco alcuni consigli più generalizzata che vi possono aiutare nel lungo periodo: http://msdn.microsoft.com/en-us/library/ms714657%28VS.85%29.aspx
Suggerimento: dovrebbe sempre ottenere SessionState da ExecutionContext del cmdlet. – x0n
Sembra che tu stia cercando [PSCmdlet.GetUnresolvedProviderPathFromPSPath Method] (http://msdn.microsoft.com/en-us/library/system.management.automation.pscmdlet.getunresolvedproviderpathfrompspath (v = VS.85) .aspx) –
Questa è stata la mia salvezza. Saluto! – Simon