@@ -1311,35 +1311,36 @@ protected override void GetItem(string path)
1311
1311
// If we want to retrieve the file streams, retrieve them.
1312
1312
if ( retrieveStreams )
1313
1313
{
1314
- if ( ! isContainer )
1314
+ foreach ( string desiredStream in dynamicParameters . Stream )
1315
1315
{
1316
- foreach ( string desiredStream in dynamicParameters . Stream )
1317
- {
1318
- // See that it matches the name specified
1319
- WildcardPattern p = WildcardPattern . Get ( desiredStream , WildcardOptions . IgnoreCase | WildcardOptions . CultureInvariant ) ;
1320
- bool foundStream = false ;
1316
+ // See that it matches the name specified
1317
+ WildcardPattern p = WildcardPattern . Get ( desiredStream , WildcardOptions . IgnoreCase | WildcardOptions . CultureInvariant ) ;
1318
+ bool foundStream = false ;
1321
1319
1322
- foreach ( AlternateStreamData stream in AlternateDataStreamUtilities . GetStreams ( result . FullName ) )
1320
+ foreach ( AlternateStreamData stream in AlternateDataStreamUtilities . GetStreams ( result . FullName ) )
1321
+ {
1322
+ if ( ! p . IsMatch ( stream . Stream ) )
1323
1323
{
1324
- if ( ! p . IsMatch ( stream . Stream ) ) { continue ; }
1325
-
1326
- string outputPath = result . FullName + ":" + stream . Stream ;
1327
- WriteItemObject ( stream , outputPath , isContainer ) ;
1328
- foundStream = true ;
1324
+ continue ;
1329
1325
}
1330
1326
1331
- if ( ( ! WildcardPattern . ContainsWildcardCharacters ( desiredStream ) ) && ( ! foundStream ) )
1332
- {
1333
- string errorMessage = StringUtil . Format (
1334
- FileSystemProviderStrings . AlternateDataStreamNotFound , desiredStream , result . FullName ) ;
1335
- Exception e = new FileNotFoundException ( errorMessage , result . FullName ) ;
1336
-
1337
- WriteError ( new ErrorRecord (
1338
- e ,
1339
- "AlternateDataStreamNotFound" ,
1340
- ErrorCategory . ObjectNotFound ,
1341
- path ) ) ;
1342
- }
1327
+ string outputPath = result . FullName + ":" + stream . Stream ;
1328
+ // Alternate data streams can never be containers.
1329
+ WriteItemObject ( stream , outputPath , isContainer : false ) ;
1330
+ foundStream = true ;
1331
+ }
1332
+
1333
+ if ( ( ! WildcardPattern . ContainsWildcardCharacters ( desiredStream ) ) && ( ! foundStream ) )
1334
+ {
1335
+ string errorMessage = StringUtil . Format (
1336
+ FileSystemProviderStrings . AlternateDataStreamNotFound , desiredStream , result . FullName ) ;
1337
+ Exception e = new FileNotFoundException ( errorMessage , result . FullName ) ;
1338
+
1339
+ WriteError ( new ErrorRecord (
1340
+ e ,
1341
+ "AlternateDataStreamNotFound" ,
1342
+ ErrorCategory . ObjectNotFound ,
1343
+ path ) ) ;
1343
1344
}
1344
1345
}
1345
1346
}
@@ -6663,7 +6664,14 @@ public IContentReader GetContentReader(string path)
6663
6664
6664
6665
try
6665
6666
{
6666
- if ( Directory . Exists ( path ) )
6667
+ // Get-Content will write a non-terminating error if the target is a directory.
6668
+ // On Windows, the streamName must be null or empty for it to write the error. Otherwise, the
6669
+ // alternate data stream is not a directory, even if it's set on a directory.
6670
+ if ( Directory . Exists ( path )
6671
+ #if ! UNIX
6672
+ & & string . IsNullOrEmpty ( streamName )
6673
+ #endif
6674
+ )
6667
6675
{
6668
6676
string errMsg = StringUtil . Format ( SessionStateStrings . GetContainerContentException , path ) ;
6669
6677
ErrorRecord error = new ErrorRecord ( new InvalidOperationException ( errMsg ) , "GetContainerContentException" , ErrorCategory . InvalidOperation , null ) ;
@@ -6818,7 +6826,14 @@ public IContentWriter GetContentWriter(string path)
6818
6826
6819
6827
try
6820
6828
{
6821
- if ( Directory . Exists ( path ) )
6829
+ // Add-Content and Set-Content will write a non-terminating error if the target is a directory.
6830
+ // On Windows, the streamName must be null or empty for it to write the error. Otherwise, the
6831
+ // alternate data stream is not a directory, even if it's set on a directory.
6832
+ if ( Directory . Exists ( path )
6833
+ #if ! UNIX
6834
+ & & string . IsNullOrEmpty ( streamName )
6835
+ #endif
6836
+ )
6822
6837
{
6823
6838
string errMsg = StringUtil . Format ( SessionStateStrings . WriteContainerContentException , path ) ;
6824
6839
ErrorRecord error = new ErrorRecord ( new InvalidOperationException ( errMsg ) , "WriteContainerContentException" , ErrorCategory . InvalidOperation , null ) ;
@@ -6896,13 +6911,6 @@ public void ClearContent(string path)
6896
6911
6897
6912
path = NormalizePath ( path ) ;
6898
6913
6899
- if ( Directory . Exists ( path ) )
6900
- {
6901
- string errorMsg = StringUtil . Format ( SessionStateStrings . ClearDirectoryContent , path ) ;
6902
- WriteError ( new ErrorRecord ( new NotSupportedException ( errorMsg ) , "ClearDirectoryContent" , ErrorCategory . InvalidOperation , path ) ) ;
6903
- return ;
6904
- }
6905
-
6906
6914
try
6907
6915
{
6908
6916
#if ! UNIX
@@ -6954,6 +6962,26 @@ public void ClearContent(string path)
6954
6962
clearStream = false ;
6955
6963
}
6956
6964
6965
+ #endif
6966
+ // On Windows, determine if our argument is a directory only after we determine if
6967
+ // we're being asked to work with an alternate data stream, because directories can have
6968
+ // alternate data streams on them that are not child items. These alternate data streams
6969
+ // must be treated as data streams, even if they're attached to directories. However,
6970
+ // if asked to work with a directory without a data stream specified, write a non-terminating
6971
+ // error instead of clearing all child items of the directory. (On non-Windows, alternate
6972
+ // data streams don't exist, so in that environment always write the error when addressing
6973
+ // a directory.)
6974
+ if ( Directory . Exists ( path )
6975
+ #if ! UNIX
6976
+ & & ! clearStream
6977
+ #endif
6978
+ )
6979
+ {
6980
+ string errorMsg = StringUtil . Format ( SessionStateStrings . ClearDirectoryContent , path ) ;
6981
+ WriteError ( new ErrorRecord ( new NotSupportedException ( errorMsg ) , "ClearDirectoryContent" , ErrorCategory . InvalidOperation , path ) ) ;
6982
+ return ;
6983
+ }
6984
+ #if ! UNIX
6957
6985
if ( clearStream )
6958
6986
{
6959
6987
FileStream fileStream = null ;
@@ -8625,7 +8653,22 @@ internal static List<AlternateStreamData> GetStreams(string path)
8625
8653
SafeFindHandle handle = NativeMethods . FindFirstStreamW (
8626
8654
path , NativeMethods . StreamInfoLevels . FindStreamInfoStandard ,
8627
8655
findStreamData , 0 ) ;
8628
- if ( handle . IsInvalid ) throw new Win32Exception ( ) ;
8656
+
8657
+ if ( handle . IsInvalid )
8658
+ {
8659
+ int error = Marshal . GetLastWin32Error ( ) ;
8660
+
8661
+ // Directories don't normally have alternate streams, so this is not an exceptional state.
8662
+ // If a directory has no alternate data streams, FindFirstStreamW returns ERROR_HANDLE_EOF.
8663
+ if ( error == NativeMethods . ERROR_HANDLE_EOF )
8664
+ {
8665
+ return alternateStreams ;
8666
+ }
8667
+
8668
+ // An unexpected error was returned, that we don't know how to interpret. The most helpful
8669
+ // thing we can do at this point is simply throw the raw Win32 exception.
8670
+ throw new Win32Exception ( error ) ;
8671
+ }
8629
8672
8630
8673
try
8631
8674
{
@@ -8760,6 +8803,7 @@ internal static void SetZoneOfOrigin(string path, SecurityZone securityZone)
8760
8803
internal static class NativeMethods
8761
8804
{
8762
8805
internal const int ERROR_HANDLE_EOF = 38 ;
8806
+ internal const int ERROR_INVALID_PARAMETER = 87 ;
8763
8807
8764
8808
internal enum StreamInfoLevels { FindStreamInfoStandard = 0 }
8765
8809
0 commit comments