Last active
December 17, 2024 02:50
-
-
Save santisq/2e33c8fa60f03951b92da850b5e4f4b1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add-Type @' | |
using System; | |
using System.Collections.Generic; | |
using System.Collections.ObjectModel; | |
using System.ComponentModel; | |
using System.IO; | |
using System.Management.Automation; | |
using System.Runtime.InteropServices; | |
using Microsoft.PowerShell.Commands; | |
[Cmdlet(VerbsCommon.Get, "ShortPathName")] | |
[OutputType(typeof(string))] | |
public sealed class GetShortPathNameCommand : CmdletWithPathBase | |
{ | |
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] | |
private extern static int GetShortPathNameW( | |
string lpszLongPath, char[] lpszShortPath, int cchBuffer); | |
[Parameter(Position = 1)] | |
public int MaxLength { get; set; } = 500; | |
protected override void ProcessRecord() | |
{ | |
int len; | |
char[] buffer = new char[MaxLength]; | |
foreach (string path in EnumerateResolvedPaths(validateExists: false)) | |
{ | |
if ((len = GetShortPathNameW(path, buffer, buffer.Length)) == 0) | |
{ | |
WriteError(new ErrorRecord( | |
new Win32Exception(Marshal.GetLastWin32Error()), | |
"WellSh...", | |
ErrorCategory.InvalidResult, | |
path)); | |
continue; | |
} | |
WriteObject(new string(buffer, 0, len)); | |
} | |
} | |
} | |
[EditorBrowsable(EditorBrowsableState.Never)] | |
public abstract class CmdletWithPathBase : PSCmdlet | |
{ | |
private bool _isLiteral; | |
private string[] _paths = []; | |
[Parameter( | |
Position = 0, | |
Mandatory = true, | |
ValueFromPipeline = true, | |
ValueFromPipelineByPropertyName = true, | |
ParameterSetName = "Path")] | |
[SupportsWildcards] | |
[ValidateNotNullOrEmpty] | |
public string[] Path | |
{ | |
get => _paths; | |
set => _paths = value; | |
} | |
[Parameter( | |
Mandatory = true, | |
ValueFromPipelineByPropertyName = true, | |
ParameterSetName = "LiteralPath")] | |
[Alias("PSPath")] | |
[ValidateNotNullOrEmpty] | |
public string[] LiteralPath | |
{ | |
get => _paths; | |
set | |
{ | |
_paths = value; | |
_isLiteral = true; | |
} | |
} | |
protected IEnumerable<string> EnumerateResolvedPaths(bool validateExists = true) | |
{ | |
Collection<string> resolvedPaths; | |
ProviderInfo provider; | |
foreach (string path in _paths) | |
{ | |
if (_isLiteral) | |
{ | |
string resolved = SessionState.Path | |
.GetUnresolvedProviderPathFromPSPath(path, out provider, out _); | |
if (!WriteErrorIfInvalidProvider(resolved, provider) | |
&& !WriteErrorIfNotExists(resolved, validateExists)) | |
{ | |
yield return resolved; | |
} | |
continue; | |
} | |
try | |
{ | |
resolvedPaths = GetResolvedProviderPathFromPSPath(path, out provider); | |
} | |
catch (Exception exception) | |
{ | |
WriteError(new ErrorRecord( | |
exception, "ResolvePath", ErrorCategory.ObjectNotFound, path)); | |
continue; | |
} | |
foreach (string resolvedPath in resolvedPaths) | |
{ | |
if (WriteErrorIfInvalidProvider(resolvedPath, provider)) | |
{ | |
continue; | |
} | |
yield return resolvedPath; | |
} | |
} | |
} | |
private bool WriteErrorIfInvalidProvider(string path, ProviderInfo provider) | |
{ | |
if (provider.ImplementingType == typeof(FileSystemProvider)) | |
{ | |
return false; | |
} | |
ArgumentException ex = new($"The resolved path '{path}' is not a FileSystem path but '{provider.Name}'."); | |
WriteError(new ErrorRecord(ex, "InvalidProvider", ErrorCategory.InvalidArgument, path)); | |
return true; | |
} | |
private bool WriteErrorIfNotExists(string path, bool validateExists) | |
{ | |
if (!validateExists) | |
{ | |
return false; | |
} | |
if (File.Exists(path) || Directory.Exists(path)) | |
{ | |
return false; | |
} | |
ItemNotFoundException ex = new($"Cannot find path '{path}' because it does not exist."); | |
WriteError(new ErrorRecord(ex, "InvalidPath", ErrorCategory.InvalidArgument, path)); | |
return true; | |
} | |
} | |
'@ -PassThru -WA 0 -IgnoreWarnings | Import-Module -Assembly { $_.Assembly } | |
Get-ShortPathName 'C:\Program Files', 'C:\Program Files (x86)' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment