@@ -55,15 +55,59 @@ function Expand-Path {
5555 Mandatory = $false ,
5656 HelpMessage = " Will delete the file if it already exists"
5757 )]
58- [switch ] $DeleteExistingFile
58+ [switch ] $DeleteExistingFile ,
59+ # #######################################################################
60+ [Parameter (
61+ Mandatory = $false ,
62+ HelpMessage = " Will force the use of a specific drive"
63+ )]
64+ [char ] $ForceDrive = ' *' ,
65+ # #######################################################################
66+ [Parameter (
67+ Mandatory = $false ,
68+ HelpMessage = " Will throw if file does not exist"
69+ )]
70+ [switch ] $FileMustExist ,
71+ # #######################################################################
72+ [Parameter (
73+ Mandatory = $false ,
74+ HelpMessage = " Will throw if directory does not exist"
75+ )]
76+ [switch ] $DirectoryMustExist
5977 # #######################################################################
6078 )
6179
6280 begin {
6381
6482 # normalize path separators and remove double separators
65- $normalizedPath = $FilePath.Trim ().Replace(" \" , [IO.Path ]::DirectorySeparatorChar).
66- Replace(" /" , [IO.Path ]::DirectorySeparatorChar)
83+ [string ] $normalizedPath = $FilePath.Trim ().Replace(" \" , [IO.Path ]::DirectorySeparatorChar).
84+ Replace(" /" , [IO.Path ]::DirectorySeparatorChar);
85+
86+ if ($normalizedPath.StartsWith ([IO.Path ]::DirectorySeparatorChar + [IO.Path ]::DirectorySeparatorChar)) {
87+
88+ $normalizedPath = [IO.Path ]::DirectorySeparatorChar + [IO.Path ]::DirectorySeparatorChar +
89+ $normalizedPath.Substring (2 ).Replace(
90+ [IO.Path ]::DirectorySeparatorChar + [IO.Path ]::DirectorySeparatorChar,
91+ [IO.Path ]::DirectorySeparatorChar
92+ )
93+
94+ if (($ForceDrive -ne ' *' ) -and
95+ (" ABCDEFGHIJKLMNOPQRSTUVWXYZ" .IndexOf(($ForceDrive -as [string ]).ToUpperInvariant()) -ge 0 )) {
96+
97+ $i = $normalizedPath.IndexOf ([IO.Path ]::DirectorySeparatorChar, 2 );
98+ $normalizedPath = $ForceDrive + " :" + (
99+
100+ $i -lt 0 ? ([IO.Path ]::DirectorySeparatorChar) : $normalizedPath.Substring ($i )
101+ )
102+ }
103+ }
104+ else {
105+
106+ $normalizedPath = $normalizedPath.Replace (
107+ [IO.Path ]::DirectorySeparatorChar + [IO.Path ]::DirectorySeparatorChar,
108+ [IO.Path ]::DirectorySeparatorChar
109+ )
110+ }
67111
68112 # check if path ends with a directory separator
69113 $hasTrailingSeparator = $normalizedPath.EndsWith (
@@ -75,14 +119,49 @@ function Expand-Path {
75119
76120 # expand home directory if path starts with ~
77121 if ($normalizedPath.StartsWith (" ~" )) {
78- $normalizedPath = Join-Path (Resolve-Path ~).Path `
79- $normalizedPath.Substring (1 )
122+
123+ if (($ForceDrive -ne ' *' ) -and
124+ (" ABCDEFGHIJKLMNOPQRSTUVWXYZ" .IndexOf(($ForceDrive -as [string ]).ToUpperInvariant()) -ge 0 )) {
125+
126+ $i = $normalizedPath.IndexOf ([IO.Path ]::DirectorySeparatorChar, 1 );
127+ $normalizedPath = $ForceDrive + " :" + (
128+
129+ $i -lt 0 ? [IO.Path ]::DirectorySeparatorChar + " **" + [IO.Path ]::DirectorySeparatorChar : (" \**" + $normalizedPath.Substring ($i ))
130+ )
131+ }
132+ else {
133+
134+ $normalizedPath = Join-Path (Convert-Path ~) `
135+ $normalizedPath.Substring (1 )
136+ }
80137 }
81138
82- # handle absolute paths (drive letter or UNC)
83139 if ((($normalizedPath.Length -gt 1 ) -and
84- ($normalizedPath.Substring (1 , 1 ) -eq " :" )) -or
85- $normalizedPath.StartsWith (" \\" )) {
140+ ($normalizedPath.Substring (1 , 1 ) -eq " :" ))) {
141+
142+ if (($ForceDrive -ne ' *' ) -and
143+ (" ABCDEFGHIJKLMNOPQRSTUVWXYZ" .IndexOf(($ForceDrive -as [string ]).ToUpperInvariant()) -ge 0 )) {
144+ $i = $normalizedPath.IndexOf ([IO.Path ]::DirectorySeparatorChar);
145+ $normalizedPath = $ForceDrive + " :" + [IO.Path ]::DirectorySeparatorChar + (($i -eq -1 -and $normalizedPath.Length -gt 2 ) -or $i -eq 2 ? " **" + [IO.Path ]::DirectorySeparatorChar : " " ) + $normalizedPath.Substring (2 )
146+ }
147+ else {
148+
149+ if (($normalizedPath.Length -lt 3 ) -or ($normalizedPath.Substring (2 , 1 ) -ne [System.IO.Path ]::DirectorySeparatorChar)) {
150+
151+ Push-Location $normalizedPath.Substring (0 , 2 )
152+ try {
153+ $normalizedPath = " $ ( Get-Location ) $ ( [IO.Path ]::DirectorySeparatorChar) $ ( $normalizedPath.Substring (2 )) "
154+ $normalizedPath = [System.IO.Path ]::GetFullPath($normalizedPath )
155+ }
156+ finally {
157+ Pop-Location
158+ }
159+ }
160+ }
161+ }
162+
163+ # handle absolute paths (drive letter or UNC)
164+ if ($normalizedPath.StartsWith ([IO.Path ]::DirectorySeparatorChar + [IO.Path ]::DirectorySeparatorChar)) {
86165
87166 try {
88167 $normalizedPath = [System.IO.Path ]::GetFullPath($normalizedPath )
@@ -92,6 +171,40 @@ function Expand-Path {
92171 }
93172 }
94173 else {
174+
175+ if (($ForceDrive -ne ' *' ) -and
176+ (" ABCDEFGHIJKLMNOPQRSTUVWXYZ" .IndexOf(($ForceDrive -as [string ]).ToUpperInvariant()) -ge 0 )) {
177+
178+ if ($normalizedPath.Length -lt 2 -or $normalizedPath.Substring (1 , 1 ) -ne " :" ) {
179+
180+ $newPath = $ForceDrive + " :" + [IO.Path ]::DirectorySeparatorChar;
181+
182+ while ($normalizedPath.StartsWith (" ." )) {
183+
184+ $i = $normalizedPath.IndexOf ([IO.Path ]::DirectorySeparatorChar);
185+ if ($i -lt 0 ) {
186+
187+ $normalizedPath = " "
188+ }
189+ else {
190+
191+ $normalizedPath = $normalizedPath.Substring ($i + 1 )
192+ }
193+ }
194+
195+ if ($normalizedPath.StartsWith ([IO.Path ]::DirectorySeparatorChar)) {
196+
197+ $newPath += $normalizedPath
198+ }
199+ else {
200+
201+ $newPath += " **" + [IO.Path ]::DirectorySeparatorChar + $normalizedPath
202+ }
203+
204+ $normalizedPath = $newPath
205+ }
206+ }
207+
95208 # handle relative paths
96209 try {
97210 $normalizedPath = [System.IO.Path ]::GetFullPath(
@@ -102,6 +215,30 @@ function Expand-Path {
102215 }
103216 }
104217
218+ # handle directory/file creation if requested
219+ if ($DirectoryMustExist -or $FileMustExist ) {
220+
221+ # get directory path accounting for trailing separator
222+ $directoryPath = if ($hasTrailingSeparator ) {
223+ [IO.Path ]::TrimEndingDirectorySeparator($normalizedPath )
224+ }
225+ else {
226+ [IO.Path ]::TrimEndingDirectorySeparator(
227+ [System.IO.Path ]::GetDirectoryName($normalizedPath ))
228+ }
229+
230+ # create directory if it doesn't exist
231+ if ($DirectoryMustExist -and (-not [IO.Directory ]::Exists($directoryPath ))) {
232+
233+ throw " Directory does not exist: $directoryPath "
234+ }
235+
236+ if ($FileMustExist -and (-not [IO.File ]::Exists($normalizedPath ))) {
237+
238+ throw " File does not exist: $normalizedPath "
239+ }
240+ }
241+
105242 # handle directory/file creation if requested
106243 if ($CreateDirectory -or $CreateFile ) {
107244
0 commit comments