WindowsPath.psm1

#Requires -Version 7.0
using namespace 'System'
using namespace 'System.IO'
using namespace 'System.Management.Automation'
Class WindowsPath {
WindowsPath([string] $Path) {
If (!!($WinPath = [WindowsPath]::GetFullPath($Path))) { $This | Add-Member ScriptProperty 'Path' { [CmdletBinding()][OutputType([string])] Param () $Script:WinPath }.GetNewClosure() }
Else { Throw 'The string "{0}" is not a valid Windows path string.' -f $Path }
}
Static [string] GetFullPath([string] $PathToValidate) {
If ([string]::IsNullOrWhiteSpace($PathToValidate) -or (& { $args[0] -imatch '[^ ]\s+([/\\]|$)' } $PathToValidate)) { Return $Null }
$IPv6RegExp = '((([a-f\d]{1,4}:){7,7}[a-f\d]{1,4}|([a-f\d]{1,4}:){1,7}:|([a-f\d]{1,4}:){1,6}:[a-f\d]{1,4}|([a-f\d]{1,4}:){1,5}(:[a-f\d]{1,4}){1,2}|([a-f\d]{1,4}:){1,4}(:[a-f\d]{1,4}){1,3}|([a-f\d]{1,4}:){1,3}(:[a-f\d]{1,4}){1,4}|([a-f\d]{1,4}:){1,2}(:[a-f\d]{1,4}){1,5}|[a-f\d]{1,4}:((:[a-f\d]{1,4}){1,6})|:((:[a-f\d]{1,4}){1,7}|:)|fe80:(:[a-f\d]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([a-f\d]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])))'
$IPv4RegExp = '((\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3})'
$HostNameRegExp = '([a-z\d\-]+(\.[a-z\d\-]+)*)'
$ShareNameRegExp = '([^"/\\\[\]:\|\<\>\+=;,\?\*]+)'
$DriveRegExp = '([^;~/\\\.:]+:)'
$RelativeElmtRegExp = '(~|\.{1,2}|[^"/\\:\|\<\>\?\*]+)'
$PathRegExp = '(([/\\]+[^"/\\:\|\<\>\?\*]*)*)'
$RegExp = '(((?<Share>^(/{{2}}|\\{{2}})({0}|{1}|{2})[/\\]+{3})|((?<Drive>^{4})(?<Cwd>[^"/\\:\|\<\>\?\*]*))|(?<Relative>^{5}))(?<Path>{6}$))|(?<Path>^{6}$)' -f @($IPv6RegExp,$IPv4RegExp,$HostNameRegExp,$ShareNameRegExp,$DriveRegExp,$RelativeElmtRegExp,$PathRegExp)
If ($PathToValidate -imatch $RegExp) {
${Function:Remove-MatchIntKeys} = { ForEach ($key in @($args[0].Value.keys)) { If ($key -inotin $args[1]) { $args[0].Value.Remove($key) } } }
Remove-MatchIntKeys ([ref] $Matches) @('Share','Drive','Cwd','Relative','Path')
$Matches.Where{ 'Share' -in $_.keys }.ForEach{
If ([Directory]::Exists($_.Share)) { $_.FullPath = Join-Path $_.Share $_.Path }
ElseIf (& { $args[0] -imatch ('(?<Path>^{0}$)' -f $PathRegExp) } $_.Share) {
$_.Path = Join-Path $_.Share $_.Path
$_.Remove('Share')
}
}
Switch ($Matches) {
{ 'Drive' -in $_.keys } {
If (($PSDrive = Get-PSDrive -Name ($_.Drive -replace ':$') -PSProvider FileSystem -ErrorAction SilentlyContinue)) {
$_.FullPath = Join-Path $PSDrive.Root ((($_.Cwd -or !$_.Path ? ($PSDrive.CurrentLocation ? (@($PSDrive.CurrentLocation,$_.Cwd) -join '\'):($_.Cwd)):'') -replace '[/\\]+$') + (($_.Path = $_.Path -replace '[/\\]+$') ? ('\' + $_.Path):$Null))
}
}
{ 'Relative' -in $_.keys } {
If ($_.Relative -in @('~','.','..')) { $_.FullPath = Join-Path ("$(Resolve-Path $_.Relative -ErrorAction Stop)" -split '::',2)[-1] $_.Path }
Else { $_.FullPath = Join-Path $PWD.ProviderPath (Join-Path $_.Relative $_.Path) }
}
}
If ('FullPath' -in @($Matches.keys)) { Remove-MatchIntKeys ([ref] $Matches) @('FullPath') }
}
If (!$Matches.FullPath -and (($Matches.Share -and $Matches.Path) -or $PathToValidate -imatch ('(?<Path>^{0}$)' -f $PathRegExp))) {
$Matches.FullPath = Join-Path "$(Try { Resolve-Path '\' -ErrorAction Stop } Catch { & {
[void] ($PWD.ProviderPath -imatch '(?<Share>\\{2}[^/\\]+\\+[^/\\]+(\\|$))')
$Matches.Share
} })"
 $Matches.Path
}
If ('FullPath' -in @($Matches.keys)) {
$Index0,$Index1,$PathSegmentList = $Matches.FullPath?.Split([char[]](47,92),[StringSplitOptions]::RemoveEmptyEntries).Where{ $_ -ne '.'}
Switch ($Matches) {
{ $_.FullPath -like '\\*' -or $_.FullPath -like '//*' } { $_.Prefix = '\\{0}\{1}\' -f $Index0,$Index1 }
Default {
$_.Prefix = "$Index0\"
$PathSegmentList = @($Index1) + $PathSegmentList
}
}
$CurrentSegmentIndex = 1
While ($CurrentSegmentIndex -lt $PathSegmentList.Count) {
If ($CurrentSegmentIndex -gt 0 -and $PathSegmentList[$CurrentSegmentIndex] -eq '..' -and $PathSegmentList[$CurrentSegmentIndex - 1] -ne '..') {
$PathSegmentList[$CurrentSegmentIndex - 1] = $PathSegmentList[$CurrentSegmentIndex] = $Null
$PathSegmentList = $PathSegmentList.Where{ $_ }
$CurrentSegmentIndex--
}
Else { $CurrentSegmentIndex++ }
}
$Matches.FullPath = Join-Path $Matches.Prefix (($PathSegmentList.Where({ $_ -ne '..' }, 'SkipUntil') -Join '\') -replace '[/\\]+$')
}
Return $Matches.FullPath
}
[string] ToString() { Return $This.Path }
}
Class ValidateWindowsPathAttribute : ValidateArgumentsAttribute {
[void] Validate([object] $PathToValidate, [EngineIntrinsics] $EngineIntrinsics) {
[WindowsPath]::New($PathToValidate)
}
}
Class ValidateWindowsFileNameAttribute : ValidateArgumentsAttribute {
[void] Validate([object] $FileNameToValidate, [EngineIntrinsics] $EngineIntrinsics) {
If (!("$FileNameToValidate" -imatch '^[^"/\\:\|\<\>\?\*]+[^"/\\:\|\<\>\?\*\s]+$' -and $Matches[0] -inotmatch '^\.{1,2}$'))
{ Throw 'The string "{0}" is not a valid Windows file name string.' -f $FileNameToValidate }
}
}