programing

PowerShell cmdlet을 작성할 때 경로를 처리하는 방법은 무엇입니까?

newstyles 2023. 8. 22. 21:59

PowerShell cmdlet을 작성할 때 경로를 처리하는 방법은 무엇입니까?

C# cmdlet을 작성할 때 파일을 매개 변수로 받는 올바른 방법은 무엇입니까?지금까지는 문자열인 LiterPath(파라미터 명명 규칙에 따라 정렬됨) 속성만 가지고 있습니다.이것은 콘솔에 입력된 모든 것(전체 경로 또는 상대 경로일 수 있음)을 입력하기 때문에 문제가 됩니다.

경로 사용.GetFullPath(문자열)가 작동하지 않습니다.제가 지금 ~에 있는 것 같아요, 아닌 것 같아요.속성을 문자열에서 FileInfo로 변경해도 동일한 문제가 발생합니다.

편집: 관심 있는 모든 사용자에게 이 해결 방법은 다음과 같습니다.

    SessionState ss = new SessionState();
    Directory.SetCurrentDirectory(ss.Path.CurrentFileSystemLocation.Path);

    LiteralPath = Path.GetFullPath(LiteralPath);

LiteralPath는 문자열 매개 변수입니다.매개 변수로 전달되는 파일 경로를 처리하는 권장 방법이 무엇인지 알고 싶습니다.

EDIT2: 이것이 더 낫습니다. 사용자의 현재 디렉터리를 어지럽히지 않으려면 디렉터리를 다시 설정해야 합니다.

            string current = Directory.GetCurrentDirectory();
            Directory.SetCurrentDirectory(ss.Path.CurrentFileSystemLocation.Path);
            LiteralPath = Path.GetFullPath(LiteralPath);
            Directory.SetCurrentDirectory(current);

이 분야는 놀라울 정도로 복잡하지만, 저는 여기서 많은 경험을 가지고 있습니다.간단히 말해서, 시스템에서 직접 win32 경로를 허용하는 cmdlet이 있습니다.IO API는 일반적으로 -FilePath 매개 변수를 사용합니다.제대로 작동하는 "powershelly" cmdlet을 작성하려면 파이프라인 입력을 수락하고 상대적이고 절대적인 공급자 경로로 작업하려면 -Path 및 -LiteralPath가 필요합니다.다음은 제가 얼마 전에 쓴 블로그 게시물에서 발췌한 것입니다.

PowerShell의 경로는 [처음에는] 이해하기 어렵습니다.PowerShell 경로(또는 PSPath)는 Win32 경로와 혼동하지 않도록 절대적인 형태로 두 가지 다른 맛이 있습니다.

  • 제공업체 인증:FileSystem::c:\temp\foo.txt
  • PS 드라이브 인증:c:\temp\foo.txt

프로바이더 내부 문제로 혼동하기 쉽습니다.ProviderPath결의 재산System.Management.Automation.PathInfo의 오른쪽 부분::(위의 공급자 인증 경로) 및 드라이브 인증 경로는 기본 FileSystem 공급자 드라이브를 보면 동일하게 보이기 때문입니다.즉, PSDrive의 이름(C)은 네이티브 백업 저장소인 윈도우즈 파일 시스템(C)과 동일합니다.따라서 차이점을 쉽게 이해할 수 있도록 다음과 같이 새로운 PSDrive를 만듭니다.

ps c:\> new-psdrive temp filesystem c:\temp\
ps c:\> cd temp:
ps temp:\>

이제 다시 한 번 살펴보겠습니다.

  • 인증:FileSystem::c:\temp\foo.txt
  • 인증:temp:\foo.txt

이번에는 무엇이 다른지 보는 것이 조금 더 쉽습니다.공급자 이름 오른쪽의 굵은 글씨는 공급자 경로입니다.

따라서 경로를 수용하는 일반화된 공급자 친화적인 Cmdlet(또는 고급 함수)을 작성하는 목표는 다음과 같습니다.

  • 를 합니다.LiteralPath 변수 - " " " " : " " " " 로 .PSPath
  • 를 합니다.Path매개 변수(와일드카드/glob을 확인함)
  • 항상 기본 제공자 경로가 아닌 PSP 경로(예: Win32 경로)를 수신하고 있다고 가정합니다.

3번 포인트는 특히 중요합니다.또한, 분히명.LiteralPath그리고.Path상호 배타적 매개 변수 집합에 속해야 합니다.

상대 경로

좋은 질문은 Cmdlet으로 전달되는 상대 경로를 어떻게 처리할 것인가 하는 것입니다.제공되는 모든 경로가 PSPath라고 가정해야 하므로 아래 Cmdlet이 수행하는 작업을 살펴보겠습니다.

ps temp:\> write-zip -literalpath foo.txt

명령어는 foo로 가정해야 합니다.txt는 현재 드라이브에 있으므로 다음과 같이 ProcessRecord 또는 EndProcessing 블록에서 즉시 해결해야 합니다(여기서 설명하는 API 사용).

$provider = $null;
$drive = $null
$pathHelper = $ExecutionContext.SessionState.Path
$providerPath = $pathHelper.GetUnresolvedProviderPathFromPSPath(
    "foo.txt", [ref]$provider, [ref]$drive)

이제 두 가지 절대 형식의 PSPath를 재생성하는 데 필요한 모든 것이 완료되었으며 기본 절대 공급자 경로도 확보되었습니다.foo에 대한 제공자의 정규화된 PSP 경로를 생성하려면 다음과 같이 하십시오.txt, 사용$provider.Name + “::” + $providerPath.한다면$drive아닙니다$null이 있는 곳일 수 .)$drive▁▁be 될 것입니다.$null그러면 당신은 사용해야 합니다.$drive.name + ":\" + $drive.CurrentLocation + "\" + "foo.txt"드라이브 인증 PSPath를 취득할 수 있습니다.

퀵스타트 C# 스켈레톤

다음은 C# 공급자 인식 cmdlet의 골격입니다.파일 시스템 공급자 경로가 전달되었는지 확인하기 위해 검사 기능이 내장되어 있습니다.나는 다른 사람들이 잘 작동하는 공급자 인식 Cmdlet을 작성할 수 있도록 돕기 위해 NuGet을 위해 이것을 포장하는 중입니다.

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

Cmdlet 개발 지침(마이크로소프트)

여기 장기적으로 도움이 될 몇 가지 일반화된 조언이 있습니다: http://msdn.microsoft.com/en-us/library/ms714657%28VS.85%29.aspx .

언급URL : https://stackoverflow.com/questions/8505294/how-do-i-deal-with-paths-when-writing-a-powershell-cmdlet