@@ -49,6 +49,8 @@ internal class InstallHelper : PSCmdlet
4949 private string _specifiedPath ;
5050 private bool _asNupkg ;
5151 private bool _includeXML ;
52+ private bool _noClobber ;
53+ List < string > _pathsToSearch ;
5254
5355 #endregion
5456
@@ -72,25 +74,24 @@ public void InstallPackages(
7274 bool reinstall ,
7375 bool force ,
7476 bool trustRepository ,
77+ bool noClobber ,
7578 PSCredential credential ,
76- string requiredResourceFile ,
77- string requiredResourceJson ,
78- Hashtable requiredResourceHash ,
7979 string specifiedPath ,
8080 bool asNupkg ,
8181 bool includeXML ,
8282 List < string > pathsToInstallPkg )
8383 {
8484 _cmdletPassedIn . WriteVerbose ( string . Format ( "Parameters passed in >>> Name: '{0}'; Version: '{1}'; Prerelease: '{2}'; Repository: '{3}'; " +
85- "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}';" ,
85+ "AcceptLicense: '{4}'; Quiet: '{5}'; Reinstall: '{6}'; TrustRepository: '{7}'; NoClobber: '{8}'; " ,
8686 string . Join ( "," , names ) ,
8787 ( versionRange != null ? versionRange . OriginalString : string . Empty ) ,
8888 prerelease . ToString ( ) ,
8989 repository != null ? string . Join ( "," , repository ) : string . Empty ,
9090 acceptLicense . ToString ( ) ,
9191 quiet . ToString ( ) ,
9292 reinstall . ToString ( ) ,
93- trustRepository . ToString ( ) ) ) ;
93+ trustRepository . ToString ( ) ,
94+ noClobber . ToString ( ) ) ) ;
9495
9596 _versionRange = versionRange ;
9697 _prerelease = prerelease ;
@@ -99,12 +100,28 @@ public void InstallPackages(
99100 _reinstall = reinstall ;
100101 _force = force ;
101102 _trustRepository = trustRepository ;
103+ _noClobber = noClobber ;
102104 _credential = credential ;
103105 _specifiedPath = specifiedPath ;
104106 _asNupkg = asNupkg ;
105107 _includeXML = includeXML ;
106108 _pathsToInstallPkg = pathsToInstallPkg ;
107109
110+ // Create list of installation paths to search.
111+ _pathsToSearch = new List < string > ( ) ;
112+
113+ // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable)
114+ // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations
115+ // e.g.:
116+ // ./InstallPackagePath1/PackageA
117+ // ./InstallPackagePath1/PackageB
118+ // ./InstallPackagePath2/PackageC
119+ // ./InstallPackagePath3/PackageD
120+ foreach ( var path in _pathsToInstallPkg )
121+ {
122+ _pathsToSearch . AddRange ( Utils . GetSubDirectories ( path ) ) ;
123+ }
124+
108125 // Go through the repositories and see which is the first repository to have the pkg version available
109126 ProcessRepositories ( names , repository , _trustRepository , _credential ) ;
110127 }
@@ -209,7 +226,6 @@ private IEnumerable<PSResourceInfo> FilterByInstalledPkgs(IEnumerable<PSResource
209226 {
210227 // Create list of installation paths to search.
211228 List < string > _pathsToSearch = new List < string > ( ) ;
212- GetHelper getHelper = new GetHelper ( _cmdletPassedIn ) ;
213229 // _pathsToInstallPkg will only contain the paths specified within the -Scope param (if applicable)
214230 // _pathsToSearch will contain all resource package subdirectories within _pathsToInstallPkg path locations
215231 // e.g.:
@@ -228,6 +244,7 @@ private IEnumerable<PSResourceInfo> FilterByInstalledPkgs(IEnumerable<PSResource
228244 filteredPackages . Add ( pkg . Name , pkg ) ;
229245 }
230246
247+ GetHelper getHelper = new GetHelper ( _cmdletPassedIn ) ;
231248 // Get currently installed packages.
232249 IEnumerable < PSResourceInfo > pkgsAlreadyInstalled = getHelper . GetPackagesFromPath (
233250 name : filteredPackages . Keys . ToArray ( ) ,
@@ -410,6 +427,12 @@ private List<string> InstallPackage(IEnumerable<PSResourceInfo> pkgsToInstall, s
410427 {
411428 continue ;
412429 }
430+
431+ // If NoClobber is specified, ensure command clobbering does not happen
432+ if ( _noClobber && ! DetectClobber ( p . Name , tempDirNameVersion , parsedMetadataHashtable ) )
433+ {
434+ continue ;
435+ }
413436 }
414437
415438 // Delete the extra nupkg related files that are not needed and not part of the module/script
@@ -548,6 +571,56 @@ private bool CallAcceptLicense(PSResourceInfo p, string moduleManifest, string t
548571 return success ;
549572 }
550573
574+ private bool DetectClobber ( string pkgName , string tempDirNameVersion , Hashtable parsedMetadataHashtable )
575+ {
576+ // Get installed modules, then get all possible paths
577+ bool foundClobber = false ;
578+ GetHelper getHelper = new GetHelper ( _cmdletPassedIn ) ;
579+ IEnumerable < PSResourceInfo > pkgsAlreadyInstalled = getHelper . GetPackagesFromPath ( new string [ ] { "*" } , VersionRange . All , _pathsToSearch ) ;
580+ // user parsed metadata hash
581+ List < string > listOfCmdlets = new List < string > ( ) ;
582+ foreach ( var cmdletName in parsedMetadataHashtable [ "CmdletsToExport" ] as object [ ] )
583+ {
584+ listOfCmdlets . Add ( cmdletName as string ) ;
585+
586+ }
587+
588+ foreach ( var pkg in pkgsAlreadyInstalled )
589+ {
590+ List < string > duplicateCmdlets = new List < string > ( ) ;
591+ List < string > duplicateCmds = new List < string > ( ) ;
592+ // See if any of the cmdlets or commands in the pkg we're trying to install exist within a package that's already installed
593+ if ( pkg . Includes . Cmdlet != null && pkg . Includes . Cmdlet . Any ( ) )
594+ {
595+ duplicateCmdlets = listOfCmdlets . Where ( cmdlet => pkg . Includes . Cmdlet . Contains ( cmdlet ) ) . ToList ( ) ;
596+
597+ }
598+ if ( pkg . Includes . Command != null && pkg . Includes . Command . Any ( ) )
599+ {
600+ duplicateCmds = listOfCmdlets . Where ( commands => pkg . Includes . Command . Contains ( commands , StringComparer . InvariantCultureIgnoreCase ) ) . ToList ( ) ;
601+ }
602+ if ( duplicateCmdlets . Any ( ) || duplicateCmds . Any ( ) )
603+ {
604+
605+ duplicateCmdlets . AddRange ( duplicateCmds ) ;
606+
607+ var errMessage = string . Format (
608+ "The following commands are already available on this system: '{0}'. This module '{1}' may override the existing commands. If you still want to install this module '{1}', remove the -NoClobber parameter." ,
609+ String . Join ( ", " , duplicateCmdlets ) , pkgName ) ;
610+
611+ var ex = new ArgumentException ( errMessage ) ;
612+ var noClobberError = new ErrorRecord ( ex , "CommandAlreadyExists" , ErrorCategory . ResourceExists , null ) ;
613+
614+ _cmdletPassedIn . WriteError ( noClobberError ) ;
615+ foundClobber = true ;
616+
617+ return foundClobber ;
618+ }
619+ }
620+
621+ return foundClobber ;
622+ }
623+
551624 private void CreateMetadataXMLFile ( string dirNameVersion , string installPath , string repoName , PSResourceInfo pkg , bool isModule )
552625 {
553626 // Script will have a metadata file similar to: "TestScript_InstalledScriptInfo.xml"
0 commit comments