@@ -192,39 +192,140 @@ private void appendOneNativeArgument(ExecutionContext context, object obj, char
192
192
//
193
193
// We need to check quotes that the win32 argument parser checks which is currently
194
194
// just the normal double quotes, no other special quotes. Also note that mismatched
195
- // quotes are supported.
196
-
197
- bool needQuotes = false , followingBackslash = false ;
198
- int quoteCount = 0 ;
199
- for ( int i = 0 ; i < arg . Length ; i ++ )
200
- {
201
- if ( arg [ i ] == '"' && ! followingBackslash )
202
- {
203
- quoteCount += 1 ;
204
- }
205
- else if ( char . IsWhiteSpace ( arg [ i ] ) && ( quoteCount % 2 == 0 ) )
206
- {
207
- needQuotes = true ;
208
- }
209
-
210
- followingBackslash = arg [ i ] == '\\ ' ;
211
- }
212
-
213
- if ( needQuotes )
195
+ // quotes are supported
196
+ if ( NeedQuotes ( arg ) )
214
197
{
215
198
_arguments . Append ( '"' ) ;
216
199
_arg
10000
uments . Append ( arg ) ;
217
200
_arguments . Append ( '"' ) ;
218
201
}
219
202
else
220
203
{
204
+ #if UNIX
205
+ // On UNIX systems, we expand arguments containing wildcard expressions against
206
+ // the file system just like bash, etc.
207
+ if ( System . Management . Automation . WildcardPattern . ContainsWildcardCharacters ( arg ) )
208
+ {
209
+ // See if the current working directory is a filesystem provider location
210
+ // We won't do the expansion if it isn't since native commands can only access the file system.
211
+ var cwdinfo = Context . EngineSessionState . CurrentLocation ;
212
+
213
+ // If it's a filesystem location then expand the wildcards
214
+ if ( string . Equals ( cwdinfo . Provider . Name , Microsoft . PowerShell . Commands . FileSystemProvider . ProviderName ,
215
+ StringComparison . OrdinalIgnoreCase ) )
216
+ {
217
+ bool normalizePath = true ;
218
+ // On UNIX, paths starting with ~ are not normalized
219
+ if ( arg . Length > 0 && arg [ 0 ] == '~' )
220
+ {
221
+ normalizePath = false ;
222
+ }
223
+
224
+ // See if there are any matching paths otherwise just add the pattern as the argument
225
+ var paths = Context . EngineSessionState . InvokeProvider . ChildItem . Get ( arg , false ) ;
226
+ if ( paths . Count > 0 )
227
+ {
228
+ bool first = true ;
229
+ foreach ( var path in paths )
230
+ {
231
+ object pbo = path . BaseObject ;
232
+ if ( ! first )
233
+ {
234
+ _arguments . Append ( " " ) ;
235
+ }
236
+ else
237
+ {
238
+ if ( ! ( pbo is System . IO . FileSystemInfo ) )
239
+ {
240
+ // If the object is not a filesystem object, then just append
241
+ // the pattern unchanged
242
+ _arguments . Append ( arg ) ;
243
+ break ;
244
+ }
245
+ first = false ;
246
+ }
247
+ var expandedPath = ( pbo as System . IO . FileSystemInfo ) . FullName ;
248
+ if ( normalizePath )
249
+ {
250
+ expandedPath = Context . SessionState . Path . NormalizeRelativePath ( expandedPath , cwdinfo . ProviderPath ) ;
251
+ }
252
+ // If the path contains spaces, then add quotes around it.
253
+ if ( NeedQuotes ( expandedPath ) )
254
+ {
255
+ _arguments . Append ( "\" " ) ;
256
+ _arguments . Append ( expandedPath ) ;
257
+ _arguments . Append ( "\" " ) ;
258
+ }
259
+ else
260
+ {
261
+ _arguments . Append ( expandedPath ) ;
262
+ }
263
+ }
264
+ }
265
+ else
266
+ {
267
+ _arguments . Append ( arg ) ;
268
+ }
269
+ }
270
+ else
271
+ {
272
+ _arguments . Append ( arg ) ;
273
+ }
274
+ }
275
+ else
276
+ {
277
+ // Even if there are no wildcards, we still need to possibly
278
+ // expand ~ into the filesystem provider home directory path
279
+ ProviderInfo fileSystemProvider = Context . EngineSessionState . GetSingleProvider (
280
+ Microsoft . PowerShell . Commands . FileSystemProvider . ProviderName ) ;
281
+ string home = fileSystemProvider . Home ;
282
+ if ( string . Equals ( arg , "~" ) )
283
+ {
284
+ _arguments . Append ( home ) ;
285
+ }
286
+ else if ( arg . StartsWith ( "~/" , StringComparison . OrdinalIgnoreCase ) )
287
+ {
288
+ var replacementString = home + arg . Substring ( 1 ) ;
289
+ _arguments . Append ( replacementString ) ;
290
+ }
291
+ else
292
+ {
293
+ _arguments . Append ( arg ) ;
294
+ }
295
+ }
296
+ #else
221
297
_arguments . Append ( arg ) ;
298
+ #endif
222
299
}
223
300
}
224
301
}
225
302
} while ( list != null ) ;
226
303
}
227
304
305
+ /// <summary>
306
+ /// Check to see if the string contains spaces and therefore must be quoted.
307
+ /// </summary>
308
+ /// <param name="stringToCheck">The string to check for spaces</param>
309
+ private bool NeedQuotes ( string stringToCheck )
310
+ {
311
+ bool needQuotes = false , followingBackslash = false ;
312
+ int quoteCount = 0 ;
313
+ for ( int i = 0 ; i < stringToCheck . Length ; i ++ )
314
+ {
315
+ if ( stringToCheck [ i ] == '"' && ! followingBackslash )
316
+ {
317
+ quoteCount += 1 ;
318
+ }
319
+ else if ( char . IsWhiteSpace ( stringToCheck [ i ] ) && ( quoteCount % 2 == 0 ) )
320
+ {
321
+ needQuotes = true ;
322
+ }
323
+ followingBackslash = stringToCheck [ i ] == '\\ ' ;
324
+ }
325
+ return needQuotes ;
326
+ }
327
+
328
+
228
329
/// <summary>
229
330
/// The native command to bind to
230
331
/// </summary>
0 commit comments