20
20
using System . Security ;
21
21
using Azure . Core ;
22
22
using Azure . Identity ;
23
+ using System . Threading . Tasks ;
24
+ using System . Threading ;
23
25
24
26
namespace Microsoft . PowerShell . PSResourceGet . UtilClasses
25
27
{
@@ -42,7 +44,7 @@ public enum MetadataFileType
42
44
#region String fields
43
45
44
46
public static readonly string [ ] EmptyStrArray = Array . Empty < string > ( ) ;
45
- public static readonly char [ ] WhitespaceSeparator = new char [ ] { ' ' } ;
47
+ public static readonly char [ ] WhitespaceSeparator = new char [ ] { ' ' } ;
46
48
public const string PSDataFileExt = ".psd1" ;
47
49
public const string PSScriptFileExt = ".ps1" ;
48
50
private const string ConvertJsonToHashtableScript = @"
@@ -140,7 +142,7 @@ public static string[] GetStringArray(ArrayList list)
140
142
if ( list == null ) { return null ; }
141
143
142
144
var strArray = new string [ list . Count ] ;
143
- for ( int i = 0 ; i < list . Count ; i ++ )
145
+ for ( int i = 0 ; i < list . Count ; i ++ )
144
146
{
145
147
strArray [ i ] = list [ i ] as string ;
146
148
}
@@ -161,7 +163,7 @@ public static string[] ProcessNameWildcards(
161
163
{
162
164
isContainWildcard = true ;
163
165
errorMsgs = errorMsgsList . ToArray ( ) ;
164
- return new string [ ] { "*" } ;
166
+ return new string [ ] { "*" } ;
165
167
}
166
168
167
169
isContainWildcard = false ;
@@ -179,8 +181,8 @@ public static string[] ProcessNameWildcards(
179
181
if ( String . Equals ( name , "*" , StringComparison . InvariantCultureIgnoreCase ) )
180
182
{
181
183
isContainWildcard = true ;
182
- errorMsgs = new string [ ] { } ;
183
- return new string [ ] { "*" } ;
184
+ errorMsgs = new string [ ] { } ;
185
+ return new string [ ] { "*" } ;
184
186
}
185
187
186
188
if ( name . Contains ( "?" ) || name . Contains ( "[" ) )
@@ -275,7 +277,8 @@ public static bool TryGetVersionType(
275
277
// eg: 2.8.8.* should translate to the version range "[2.1.3.0,2.1.3.99999]"
276
278
modifiedVersion = $ "[{ versionSplit [ 0 ] } .{ versionSplit [ 1 ] } .{ versionSplit [ 2 ] } .0,{ versionSplit [ 0 ] } .{ versionSplit [ 1 ] } .{ versionSplit [ 2 ] } .999999]";
277
279
}
278
- else {
280
+ else
281
+ {
279
282
error = "Argument for -Version parameter is not in the proper format" ;
280
283
return false ;
281
284
}
@@ -469,15 +472,15 @@ public static bool TryCreateValidPSCredentialInfo(
469
472
470
473
try
471
474
{
472
- if ( ! string . IsNullOrEmpty ( ( string ) credentialInfoCandidate . Properties [ PSCredentialInfo . VaultNameAttribute ] ? . Value )
473
- && ! string . IsNullOrEmpty ( ( string ) credentialInfoCandidate . Properties [ PSCredentialInfo . SecretNameAttribute ] ? . Value ) )
475
+ if ( ! string . IsNullOrEmpty ( ( string ) credentialInfoCandidate . Properties [ PSCredentialInfo . VaultNameAttribute ] ? . Value )
476
+ && ! string . IsNullOrEmpty ( ( string ) credentialInfoCandidate . Properties [ PSCredentialInfo . SecretNameAttribute ] ? . Value ) )
474
477
{
475
478
PSCredential credential = null ;
476
479
if ( credentialInfoCandidate . Properties [ PSCredentialInfo . CredentialAttribute ] != null )
477
480
{
478
481
try
479
482
{
480
- credential = ( PSCredential ) credentialInfoCandidate . Properties [ PSCredentialInfo . CredentialAttribute ] . Value ;
483
+ credential = ( PSCredential ) credentialInfoCandidate . Properties [ PSCredentialInfo . CredentialAttribute ] . Value ;
481
484
}
482
485
catch ( Exception e )
483
486
{
@@ -492,8 +495,8 @@ public static bool TryCreateValidPSCredentialInfo(
492
495
}
493
496
494
497
repoCredentialInfo = new PSCredentialInfo (
495
- ( string ) credentialInfoCandidate . Properties [ PSCredentialInfo . VaultNameAttribute ] . Value ,
496
- ( string ) credentialInfoCandidate . Properties [ PSCredentialInfo . SecretNameAttribute ] . Value ,
498
+ ( string ) credentialInfoCandidate . Properties [ PSCredentialInfo . VaultNameAttribute ] . Value ,
499
+ ( string ) credentialInfoCandidate . Properties [ PSCredentialInfo . SecretNameAttribute ] . Value ,
497
500
credential
498
501
) ;
499
502
@@ -711,7 +714,7 @@ public static string GetContainerRegistryAccessTokenFromSecretManagement(
711
714
string password = new NetworkCredential ( string . Empty , secretSecureString ) . Password ;
712
715
return password ;
713
716
}
714
- else if ( secretValue is PSCredential psCredSecret )
717
+ else if ( secretValue is PSCredential psCredSecret )
715
718
{
716
719
string password = new NetworkCredential ( string . Empty , psCredSecret . Password ) . Password ;
717
720
return password ;
@@ -1120,7 +1123,8 @@ private static void GetStandardPlatformPaths(
1120
1123
// paths are the same for both Linux and macOS
1121
1124
localUserDir = Path . Combine ( GetHomeOrCreateTempHome ( ) , ".local" , "share" , "powershell" ) ;
1122
1125
// Create the default data directory if it doesn't exist.
1123
- if ( ! Directory . Exists ( localUserDir ) ) {
1126
+ if ( ! Directory . Exists ( localUserDir ) )
1127
+ {
1124
1128
Directory . CreateDirectory ( localUserDir ) ;
1125
1129
}
1126
1130
@@ -1247,7 +1251,7 @@ private static bool TryReadPSDataFile(
1247
1251
result = psObject . BaseObject ;
1248
1252
}
1249
1253
1250
- dataFileInfo = ( Hashtable ) result ;
1254
+ dataFileInfo = ( Hashtable ) result ;
1251
1255
error = null ;
1252
1256
return true ;
1253
1257
}
@@ -1369,10 +1373,10 @@ public static bool TryCreateModuleSpecification(
1369
1373
validatedModuleSpecs = Array . Empty < ModuleSpecification > ( ) ;
1370
1374
List < ModuleSpecification > moduleSpecsList = new List < ModuleSpecification > ( ) ;
1371
1375
1372
- foreach ( Hashtable moduleSpec in moduleSpecHashtables )
1376
+ foreach ( Hashtable moduleSpec in moduleSpecHashtables )
1373
1377
{
1374
1378
// ModuleSpecification(string) constructor for creating a ModuleSpecification when only ModuleName is provided.
1375
- if ( ! moduleSpec . ContainsKey ( "ModuleName" ) || String . IsNullOrEmpty ( ( string ) moduleSpec [ "ModuleName" ] ) )
1379
+ if ( ! moduleSpec . ContainsKey ( "ModuleName" ) || String . IsNullOrEmpty ( ( string ) moduleSpec [ "ModuleName" ] ) )
1376
1380
{
1377
1381
errorList . Add ( new ErrorRecord (
1378
1382
new ArgumentException ( $ "RequiredModules Hashtable entry { moduleSpec . ToString ( ) } is missing a key 'ModuleName' and associated value, which is required for each module specification entry") ,
@@ -1384,7 +1388,7 @@ public static bool TryCreateModuleSpecification(
1384
1388
}
1385
1389
1386
1390
// At this point it must contain ModuleName key.
1387
- string moduleSpecName = ( string ) moduleSpec [ "ModuleName" ] ;
1391
+ string moduleSpecName = ( string ) moduleSpec [ "ModuleName" ] ;
1388
1392
ModuleSpecification currentModuleSpec = null ;
1389
1393
if ( ! moduleSpec . ContainsKey ( "MaximumVersion" ) && ! moduleSpec . ContainsKey ( "ModuleVersion" ) && ! moduleSpec . ContainsKey ( "RequiredVersion" ) )
1390
1394
{
@@ -1410,10 +1414,10 @@ public static bool TryCreateModuleSpecification(
1410
1414
else
1411
1415
{
1412
1416
// ModuleSpecification(Hashtable) constructor for when ModuleName + {Required,Maximum,Module}Version value is also provided.
1413
- string moduleSpecMaxVersion = moduleSpec . ContainsKey ( "MaximumVersion" ) ? ( string ) moduleSpec [ "MaximumVersion" ] : String . Empty ;
1414
- string moduleSpecModuleVersion = moduleSpec . ContainsKey ( "ModuleVersion" ) ? ( string ) moduleSpec [ "ModuleVersion" ] : String . Empty ;
1415
- string moduleSpecRequiredVersion = moduleSpec . ContainsKey ( "RequiredVersion" ) ? ( string ) moduleSpec [ "RequiredVersion" ] : String . Empty ;
1416
- Guid moduleSpecGuid = moduleSpec . ContainsKey ( "Guid" ) ? ( Guid ) moduleSpec [ "Guid" ] : Guid . Empty ;
1417
+ string moduleSpecMaxVersion = moduleSpec . ContainsKey ( "MaximumVersion" ) ? ( string ) moduleSpec [ "MaximumVersion" ] : String . Empty ;
1418
+ string moduleSpecModuleVersion = moduleSpec . ContainsKey ( "ModuleVersion" ) ? ( string ) moduleSpec [ "ModuleVersion" ] : String . Empty ;
1419
+ string moduleSpecRequiredVersion = moduleSpec . ContainsKey ( "RequiredVersion" ) ? ( string ) moduleSpec [ "RequiredVersion" ] : String . Empty ;
1420
+ Guid moduleSpecGuid = moduleSpec . ContainsKey ( "Guid" ) ? ( Guid ) moduleSpec [ "Guid" ] : Guid . Empty ;
1417
1421
1418
1422
if ( String . IsNullOrEmpty ( moduleSpecMaxVersion ) && String . IsNullOrEmpty ( moduleSpecModuleVersion ) && String . IsNullOrEmpty ( moduleSpecRequiredVersion ) )
1419
1423
{
@@ -1536,22 +1540,36 @@ public static void DeleteDirectoryWithRestore(string dirPath)
1536
1540
/// </Summary>
1537
1541
public static void DeleteDirectory ( string dirPath )
1538
1542
{
1539
- foreach ( var dirFilePath in Directory . GetFiles ( dirPath ) )
1543
+ // Remove read only file attributes first
1544
+ foreach ( var dirFilePath in Directory . GetFiles ( dirPath , "*" , SearchOption . AllDirectories ) )
1540
1545
{
1541
1546
if ( File . GetAttributes ( dirFilePath ) . HasFlag ( FileAttributes . ReadOnly ) )
1542
1547
{
1543
- File . SetAttributes ( dirFilePath , ( File . GetAttributes ( dirFilePath ) & ~ FileAttributes . ReadOnly ) ) ;
1548
+ File . SetAttributes ( dirFilePath , File . GetAttributes ( dirFilePath ) & ~ FileAttributes . ReadOnly ) ;
1544
1549
}
1545
-
1546
- File . Delete ( dirFilePath ) ;
1547
1550
}
1548
-
1549
- foreach ( var dirSubPath in Directory . GetDirectories ( dirPath ) )
1551
+ // Delete directory recursive, try multiple times before throwing ( #1662 )
1552
+ int maxAttempts = 5 ;
1553
+ int msDelay = 5 ;
1554
+ for ( int attempt = 1 ; attempt <= maxAttempts ; ++ attempt )
1550
1555
{
1551
- DeleteDirectory ( dirSubPath ) ;
1556
+ try
1557
+ {
1558
+ Directory . Delete ( dirPath , true ) ;
1559
+ return ;
1560
+ }
1561
+ catch ( Exception ex )
1562
+ {
1563
+ if ( attempt < maxAttempts && ( ex is IOException || ex is UnauthorizedAccessException ) )
1564
+ {
1565
+ Thread . Sleep ( msDelay ) ;
1566
+ }
1567
+ else
1568
+ {
1569
+ throw ;
1570
+ }
1571
+ }
1552
1572
}
1553
-
1554
- Directory . Delete ( dirPath ) ;
1555
1573
}
1556
1574
1557
1575
/// <Summary>
0 commit comments