Function Test-ModuleInclusion { <# .SYNOPSIS Checks all the modules in the solution to see if there are obvious circular dependencies or if the module includes a higher-order include .EXAMPLE Test-ModuleInclusion .\ .PARAMETER FolderPath The name of the folder to examine all files under. .PARAMETER FailBuild Throws if this is true .PARAMETER ShowObviousCycles Show obvious cycles. This is not as important as higher-order inclusion on lower-order modules #> [CmdletBinding()] Param ( [string]$FolderPath, [switch]$FailBuild, [switch]$ShowObviousCycles ) $cSharpCode = @" using System; using System.IO; using System.Collections.Generic; using System.Linq; using System.Diagnostics; using System.Text.RegularExpressions; using System.Collections; public static class ModuleChecker { #region static decls static string[] verbs = new[] { "Add", "Approve", "Assert", "Backup", "Block", "Checkpoint", "Clear", "Close", "Compare", "Complete", "Compress", "Confirm", "Connect", "Convert", "ConvertFrom", "ConvertTo", "Copy", "Debug", "Deny", "Disable", "Disconnect", "Dismount", "Edit", "Enable", "Enter", "Exit", "Expand", "Export", "Find", "Format", "Get", "Grant", "Group", "Hide", "Import", "Initialize", "Install", "Invoke", "Join", "Limit", "Lock", "Measure", "Merge", "Mount", "Move", "New", "Open", "Optimize", "Out", "Ping", "Pop", "Protect", "Publish", "Push", "Read", "Receive", "Redo", "Register", "Remove", "Rename", "Repair", "Request", "Reset", "Resize", "Resolve", "Restart", "Restore", "Resume", "Revoke", "Save", "Search", "Select", "Send", "Set", "Show", "Skip", "Split", "Start", "Step", "Stop", "Submit", "Suspend", "Switch", "Sync", "Test", "Trace", "Unblock", "Undo", "Uninstall", "Unlock", "Unprotect", "Unpublish", "Unregister", "Update", "Use", "Wait", "Watch", "Write" }; static string[] webAdministrationFunctions = new[] { "Add-WebConfiguration", "Add-WebConfigurationLock", "Add-WebConfigurationProperty", "Backup-WebConfiguration", "Clear-WebCentralCertProvider", "Clear-WebConfiguration", "Clear-WebRequestTracingSetting", "Clear-WebRequestTracingSettings", "ConvertTo-WebApplication", "Disable-WebCentralCertProvider", "Disable-WebGlobalModule", "Disable-WebRequestTracing", "Enable-WebCentralCertProvider", "Enable-WebGlobalModule", "Enable-WebRequestTracing", "Get-WebAppDomain", "Get-WebApplication", "Get-WebAppPoolState", "Get-WebBinding", "Get-WebCentralCertProvider", "Get-WebConfigFile", "Get-WebConfiguration", "Get-WebConfigurationBackup", "Get-WebConfigurationLocation", "Get-WebConfigurationLock", "Get-WebConfigurationProperty", "Get-WebFilePath", "Get-WebGlobalModule", "Get-WebHandler", "Get-WebItemState", "Get-WebManagedModule", "Get-WebRequest", "Get-Website", "Get-WebsiteState", "Get-WebURL", "Get-WebVirtualDirectory", "New-WebApplication", "New-WebAppPool", "New-WebBinding", "New-WebFtpSite", "New-WebGlobalModule", "New-WebHandler", "New-WebManagedModule", "New-Website", "New-WebVirtualDirectory", "Remove-WebApplication", "Remove-WebAppPool", "Remove-WebBinding", "Remove-WebConfigurationBackup", "Remove-WebConfigurationLocation", "Remove-WebConfigurationLock", "Remove-WebConfigurationProperty", "Remove-WebGlobalModule", "Remove-WebHandler", "Remove-WebManagedModule", "Remove-Website", "Remove-WebVirtualDirectory", "Rename-WebConfigurationLocation", "Restart-WebAppPool", "Restart-WebItem", "Restore-WebConfiguration", "Select-WebConfiguration", "Set-WebBinding", "Set-WebCentralCertProvider", "Set-WebCentralCertProviderCredential", "Set-WebConfiguration", "Set-WebConfigurationProperty", "Set-WebGlobalModule", "Set-WebHandler", "Set-WebManagedModule", "Start-WebAppPool", "Start-WebCommitDelay", "Start-WebItem", "Start-Website", "Stop-WebAppPool", "Stop-WebCommitDelay", "Stop-WebItem", "Stop-Website" }; static string[] carbonFunctions = new[] { "Add-CGroupMember", "Add-CIisDefaultDocument", "Add-CTrustedHost", "Add-GroupMember", "Add-GroupMembers", "Add-IisDefaultDocument", "Add-TrustedHost", "Add-TrustedHosts", "Assert-AdminPrivilege", "Assert-AdminPrivileges", "Assert-CAdminPrivilege", "Assert-CFirewallConfigurable", "Assert-CService", "Assert-FirewallConfigurable", "Assert-Service", "Clear-CDscLocalResourceCache", "Clear-CMofAuthoringMetadata", "Clear-CTrustedHost", "Clear-DscLocalResourceCache", "Clear-MofAuthoringMetadata", "Clear-TrustedHost", "Clear-TrustedHosts", "Complete-CJob", "Complete-Job", "Complete-Jobs", "Compress-CItem", "Compress-Item", "Convert-CSecureStringToString", "Convert-CXmlFile", "Convert-SecureStringToString", "Convert-XmlFile", "ConvertFrom-Base64", "ConvertFrom-CBase64", "ConvertTo-Base64", "ConvertTo-CBase64", "ConvertTo-CContainerInheritanceFlags", "ConvertTo-CInheritanceFlag", "ConvertTo-CPropagationFlag", "ConvertTo-CSecurityIdentifier", "ConvertTo-ContainerInheritanceFlags", "ConvertTo-FullPath", "ConvertTo-InheritanceFlag", "ConvertTo-InheritanceFlags", "ConvertTo-PropagationFlag", "ConvertTo-PropagationFlags", "ConvertTo-SecurityIdentifier", "Copy-CDscResource", "Copy-DscResource", "Disable-AclInheritance", "Disable-CAclInheritance", "Disable-CFirewallStatefulFtp", "Disable-CIEEnhancedSecurityConfiguration", "Disable-CIisSecurityAuthentication", "Disable-CNtfsCompression", "Disable-FirewallStatefulFtp", "Disable-IEEnhancedSecurityConfiguration", "Disable-IisSecurityAuthentication", "Disable-NtfsCompression", "Enable-AclInheritance", "Enable-CAclInheritance", "Enable-CFirewallStatefulFtp", "Enable-CIEActivationPermission", "Enable-CIisDirectoryBrowsing", "Enable-CIisSecurityAuthentication", "Enable-CIisSsl", "Enable-CNtfsCompression", "Enable-FirewallStatefulFtp", "Enable-IEActivationPermission", "Enable-IEActivationPermissions", "Enable-IisDirectoryBrowsing", "Enable-IisSecurityAuthentication", "Enable-IisSsl", "Enable-NtfsCompression", "Expand-CItem", "Expand-Item", "Find-ADUser", "Find-CADUser", "Format-ADSearchFilterValue", "Format-ADSpecialCharacters", "Format-CADSearchFilterValue", "Get-ADDomainController", "Get-CADDomainController", "Get-CCertificate", "Get-CCertificateStore", "Get-CComPermission", "Get-CComSecurityDescriptor", "Get-CDscError", "Get-CDscWinEvent", "Get-CFileShare", "Get-CFileSharePermission", "Get-CFirewallRule", "Get-CGroup", "Get-CHttpUrlAcl", "Get-CIPAddress", "Get-CIisAppPool", "Get-CIisApplication", "Get-CIisConfigurationSection", "Get-CIisHttpHeader", "Get-CIisHttpRedirect", "Get-CIisMimeMap", "Get-CIisSecurityAuthentication", "Get-CIisVersion", "Get-CIisWebsite", "Get-CMsi", "Get-CMsmqMessageQueue", "Get-CMsmqMessageQueuePath", "Get-CPathProvider", "Get-CPathToHostsFile", "Get-CPerformanceCounter", "Get-CPermission", "Get-CPowerShellModuleInstallPath", "Get-CPowershellPath", "Get-CPrivilege", "Get-CProgramInstallInfo", "Get-CRegistryKeyValue", "Get-CScheduledTask", "Get-CServiceAcl", "Get-CServiceConfiguration", "Get-CServicePermission", "Get-CServiceSecurityDescriptor", "Get-CSslCertificateBinding", "Get-CTrustedHost", "Get-CUser", "Get-CWmiLocalUserAccount", "Get-Certificate", "Get-CertificateStore", "Get-ComPermission", "Get-ComPermissions", "Get-ComSecurityDescriptor", "Get-DscError", "Get-DscWinEvent", "Get-FileShare", "Get-FileSharePermission", "Get-FirewallRule", "Get-FirewallRules", "Get-Group", "Get-HttpUrlAcl", "Get-IPAddress", "Get-IisAppPool", "Get-IisApplication", "Get-IisConfigurationSection", "Get-IisHttpHeader", "Get-IisHttpRedirect", "Get-IisMimeMap", "Get-IisSecurityAuthentication", "Get-IisVersion", "Get-IisWebsite", "Get-Msi", "Get-MsmqMessageQueue", "Get-MsmqMessageQueuePath", "Get-PathCanonicalCase", "Get-PathProvider", "Get-PathToHostsFile", "Get-PerformanceCounter", "Get-PerformanceCounters", "Get-Permission", "Get-Permissions", "Get-PowerShellModuleInstallPath", "Get-PowershellPath", "Get-Privilege", "Get-Privileges", "Get-ProgramInstallInfo", "Get-RegistryKeyValue", "Get-ScheduledTask", "Get-ServiceAcl", "Get-ServiceConfiguration", "Get-ServicePermission", "Get-ServicePermissions", "Get-ServiceSecurityDescriptor", "Get-SslCertificateBinding", "Get-SslCertificateBindings", "Get-TrustedHost", "Get-TrustedHosts", "Get-User", "Get-WmiLocalUserAccount", "Grant-CComPermission", "Grant-CHttpUrlPermission", "Grant-CMsmqMessageQueuePermission", "Grant-CPermission", "Grant-CPrivilege", "Grant-CServiceControlPermission", "Grant-CServicePermission", "Grant-ComPermission", "Grant-ComPermissions", "Grant-HttpUrlPermission", "Grant-MsmqMessageQueuePermission", "Grant-MsmqMessageQueuePermissions", "Grant-Permission", "Grant-Permissions", "Grant-Privilege", "Grant-ServiceControlPermission", "Grant-ServicePermission", "Initialize-CLcm", "Initialize-Lcm", "Install-CCertificate", "Install-CDirectory", "Install-CFileShare", "Install-CGroup", "Install-CIisAppPool", "Install-CIisApplication", "Install-CIisVirtualDirectory", "Install-CIisWebsite", "Install-CJunction", "Install-CMsi", "Install-CMsmq", "Install-CMsmqMessageQueue", "Install-CPerformanceCounter", "Install-CRegistryKey", "Install-CScheduledTask", "Install-CService", "Install-CUser", "Install-Certificate", "Install-Directory", "Install-FileShare", "Install-Group", "Install-IisAppPool", "Install-IisApplication", "Install-IisVirtualDirectory", "Install-IisWebsite", "Install-Junction", "Install-Msi", "Install-Msmq", "Install-MsmqMessageQueue", "Install-PerformanceCounter", "Install-RegistryKey", "Install-ScheduledTask", "Install-Service", "Install-SmbShare", "Install-User", "Invoke-AppCmd", "Invoke-CAppCmd", "Invoke-CPowerShell", "Invoke-PowerShell", "Invoke-WindowsInstaller", "Join-CIisVirtualPath", "Join-IisVirtualPath", "Lock-CIisConfigurationSection", "Lock-IisConfigurationSection", "New-CCredential", "New-CJunction", "New-CRsaKeyPair", "New-CTempDirectory", "New-Credential", "New-Junction", "New-RsaKeyPair", "New-TempDir", "New-TempDirectory", "Protect-Acl", "Protect-CString", "Protect-String", "Read-CFile", "Read-File", "Remove-CDotNetAppSetting", "Remove-CEnvironmentVariable", "Remove-CGroupMember", "Remove-CHostsEntry", "Remove-CIisMimeMap", "Remove-CIniEntry", "Remove-CJunction", "Remove-CRegistryKeyValue", "Remove-CSslCertificateBinding", "Remove-Certificate", "Remove-DotNetAppSetting", "Remove-EnvironmentVariable", "Remove-GroupMember", "Remove-HostsEntry", "Remove-IisMimeMap", "Remove-IisWebsite", "Remove-IniEntry", "Remove-Junction", "Remove-MsmqMessageQueue", "Remove-RegistryKeyValue", "Remove-Service", "Remove-SslCertificateBinding", "Remove-User", "Reset-CHostsFile", "Reset-CMsmqQueueManagerID", "Reset-HostsFile", "Reset-MsmqQueueManagerID", "Resolve-CFullPath", "Resolve-CIdentity", "Resolve-CIdentityName", "Resolve-CNetPath", "Resolve-CPathCase", "Resolve-CRelativePath", "Resolve-FullPath", "Resolve-Identity", "Resolve-IdentityName", "Resolve-NetPath", "Resolve-PathCase", "Resolve-RelativePath", "Restart-CRemoteService", "Restart-RemoteService", "Revoke-CComPermission", "Revoke-CHttpUrlPermission", "Revoke-CPermission", "Revoke-CPrivilege", "Revoke-CServicePermission", "Revoke-ComPermission", "Revoke-ComPermissions", "Revoke-HttpUrlPermission", "Revoke-Permission", "Revoke-Privilege", "Revoke-ServicePermission", "Set-CDotNetAppSetting", "Set-CDotNetConnectionString", "Set-CEnvironmentVariable", "Set-CHostsEntry", "Set-CIisHttpHeader", "Set-CIisHttpRedirect", "Set-CIisMimeMap", "Set-CIisWebsiteID", "Set-CIisWebsiteSslCertificate", "Set-CIisWindowsAuthentication", "Set-CIniEntry", "Set-CRegistryKeyValue", "Set-CServiceAcl", "Set-CSslCertificateBinding", "Set-CTrustedHost", "Set-DotNetAppSetting", "Set-DotNetConnectionString", "Set-EnvironmentVariable", "Set-HostsEntry", "Set-IisHttpHeader", "Set-IisHttpRedirect", "Set-IisMimeMap", "Set-IisWebsiteID", "Set-IisWebsiteSslCertificate", "Set-IisWindowsAuthentication", "Set-IniEntry", "Set-RegistryKeyValue", "Set-ServiceAcl", "Set-SslCertificateBinding", "Set-TrustedHost", "Set-TrustedHosts", "Split-CIni", "Split-Ini", "Start-CDscPullConfiguration", "Start-DscPullConfiguration", "Test-AdminPrivilege", "Test-AdminPrivileges", "Test-CAdminPrivilege", "Test-CDotNet", "Test-CDscTargetResource", "Test-CFileShare", "Test-CFirewallStatefulFtp", "Test-CGroup", "Test-CGroupMember", "Test-CIPAddress", "Test-CIdentity", "Test-CIisAppPool", "Test-CIisConfigurationSection", "Test-CIisSecurityAuthentication", "Test-CIisWebsite", "Test-CMsmqMessageQueue", "Test-CNtfsCompression", "Test-COSIs32Bit", "Test-COSIs64Bit", "Test-CPathIsJunction", "Test-CPerformanceCounter", "Test-CPerformanceCounterCategory", "Test-CPermission", "Test-CPowerShellIs32Bit", "Test-CPowerShellIs64Bit", "Test-CPrivilege", "Test-CRegistryKeyValue", "Test-CScheduledTask", "Test-CService", "Test-CSslCertificateBinding", "Test-CTypeDataMember", "Test-CUncPath", "Test-CUser", "Test-CWindowsFeature", "Test-CZipFile", "Test-DotNet", "Test-DscTargetResource", "Test-FileShare", "Test-FirewallStatefulFtp", "Test-Group", "Test-GroupMember", "Test-IPAddress", "Test-Identity", "Test-IisAppPool", "Test-IisAppPoolExists", "Test-IisConfigurationSection", "Test-IisSecurityAuthentication", "Test-IisWebsite", "Test-IisWebsiteExists", "Test-MsmqMessageQueue", "Test-NtfsCompression", "Test-OSIs32Bit", "Test-OSIs64Bit", "Test-PathIsJunction", "Test-PerformanceCounter", "Test-PerformanceCounterCategory", "Test-Permission", "Test-PowerShellIs32Bit", "Test-PowerShellIs64Bit", "Test-Privilege", "Test-RegistryKeyValue", "Test-ScheduledTask", "Test-Service", "Test-SslCertificateBinding", "Test-TypeDataMember", "Test-UncPath", "Test-User", "Test-WindowsFeature", "Test-ZipFile", "Uninstall-CCertificate", "Uninstall-CDirectory", "Uninstall-CFileShare", "Uninstall-CGroup", "Uninstall-CIisAppPool", "Uninstall-CIisWebsite", "Uninstall-CJunction", "Uninstall-CMsmqMessageQueue", "Uninstall-CPerformanceCounterCategory", "Uninstall-CScheduledTask", "Uninstall-CService", "Uninstall-CUser", "Uninstall-Certificate", "Uninstall-Directory", "Uninstall-FileShare", "Uninstall-Group", "Uninstall-IisAppPool", "Uninstall-IisWebsite", "Uninstall-Junction", "Uninstall-MsmqMessageQueue", "Uninstall-PerformanceCounterCategory", "Uninstall-ScheduledTask", "Uninstall-Service", "Uninstall-User", "Unlock-CIisConfigurationSection", "Unlock-IisConfigurationSection", "Unprotect-AclAccessRules", "Unprotect-CString", "Unprotect-String", "Write-CDscError", "Write-CFile", "Write-DscError", "Write-File" }; static string[] windowsFunctions = new[] { "Add-LocalGroupMember", "Add-Member", "Add-Type", "Add-WindowsFeature", "Clear-Host", "Close-SmbOpenFile", "Compare-Object", "Compress-Certificates", "Convert-Path", "ConvertFrom-Json", "ConvertTo-JSON", "ConvertTo-Json", "ConvertTo-SecureString", "ConvertTo-Xml", "Copy-Item", "Enable-WindowsOptionalFeature", "Enter-PSSession", "Exit-PSSession", "Export-PfxCertificate", "Format-List", "Format-Table", "Get-ADComputer", "Get-ADGroupMember", "Get-ADUser", "Get-Acl", "Get-CIMInstance", "Get-ChildItem", "Get-CimInstance", "Get-Content", "Get-Date", "Get-FileHash", "Get-Host", "Get-IISAppPool", "Get-IISSite", "Get-Item", "Get-ItemProperty", "Get-ItemPropertyValue", "Get-LocalGroupMember", "Get-Location", "Get-Member", "Get-Module", "Get-NetIPAddress", "Get-NetTCPConnection", "Get-PSCallStack", "Get-Process", "Get-Random", "Get-Service", "Get-SmbOpenFile", "Get-TimeZone", "Get-Unique", "Get-Variable", "Get-WinEvent", "Get-WindowsFeature", "Get-Childitem", "Group-Object", "Import-Certificate", "Import-Csv", "Import-Module", "Import-PfxCertificate", "Install-ADServiceAccount", "Install-WindowsFeature", "Invoke-Command", "Invoke-Expression", "Invoke-Pester", "Invoke-RestMethod", "Invoke-WebRequest", "Join-Path", "Join-path", "Move-Item", "New-EventLog", "New-Item", "New-ItemProperty", "New-Object", "New-PSDrive", "New-PSSession", "New-ScheduledTaskAction", "New-ScheduledTaskTrigger", "New-Service", "New-TimeSpan", "New-Variable", "New-WebServiceProxy", "Out-File", "Out-Null", "Out-String", "Out-null", "Pop-Location", "Push-Location", "Read-Host", "Receive-Job", "Register-ScheduledTask", "Remove-Item", "Remove-PSDrive", "Remove-PSSession", "Remove-item", "Rename-Item", "Resolve-DnsName", "Resolve-Path", "Select-Object", "Select-Xml", "Select-object", "Send-MailMessage", "Set-Acl", "Set-Alias", "Set-Content", "Set-ExecutionPolicy", "Set-ItemProperty", "Set-Location", "Set-Service", "Set-Variable", "Split-Path", "Start-Job", "Start-Process", "Start-Service", "Start-Sleep", "Stop-Process", "Stop-Service", "Test-ADServiceAccount", "Test-NetConnection", "Test-Path", "Wait-Job", "Write-Debug", "Write-Error", "Write-Host", "Write-Information", "Write-Output", "Write-Verbose", "Write-Warning" ,"Restart-Computer","Restart-Service","Invoke-Item","Get-Counter","ConvertTo-Html","New-Guid"}; static string[] awsFunctions = new[] { "Remove-S3Object", "Write-S3Object", "Get-S3Object", "Copy-S3Object", "Copy-ServiceFabricApplicationPackage", "New-ASLaunchConfiguration", "Set-ASInstanceHealth", "Get-EC2Image", "Get-EC2Instance", "Get-EC2NetworkInterface", "Get-ELB2LoadBalancer", "Get-ELB2TargetGroup", "Get-ElbHealthcheckEndpoints", "Enter-ASStandby", "Exit-ASStandby", "Get-ASAutoScalingGroup", "Get-ASAutoScalingInstance", "Get-ASInstanceHealth", "Get-ASLaunchConfiguration", "Get-SSMParameter" ,"Read-S3Object","Get-ELB2TargetHealth"}; static string[] serviceFabricFunctions = new[] { "Get-ServiceFabricApplication", "Get-ServiceFabricApplicationType", "Get-ServiceFabricApplicationUpgrade", "Get-ServiceFabricClusterConfiguration", "Get-ServiceFabricClusterConfigurationUpgradeStatus", "Get-ServiceFabricDeployedApplication", "Get-ServiceFabricDeployedCodePackage", "Get-ServiceFabricNode", "Get-ServiceFabricPartition", "Get-ServiceFabricRegisteredClusterCodeVersion", "Get-ServiceFabricService", "Start-ServiceFabricApplicationUpgrade", "Start-ServiceFabricClusterConfigurationUpgrade", "Start-ServiceFabricClusterUpgrade", "Unregister-ServiceFabricApplicationType", "Update-ServiceFabricService", "Remove-ServiceFabricApplication", "Remove-ServiceFabricCluster", "Register-ServiceFabricApplicationType", "Restart-ServiceFabricDeployedCodePackage", "New-ServiceFabricApplication", "New-ServiceFabricNodeConfiguration", "Connect-ServiceFabricCluster","Invoke-MinimizeEnvironment" }; static string[] cloudbase_powershell_yaml = new[] { "ConvertFrom-Yaml", "ConvertTo-Yaml" }; static string[] redisFunctions = new[] { "Invoke-RedisScript","Add-RedisKey" }; /// /// Most of these fell out of comments because of the matching on verb-word /// static string[] ignoreRandomPhrases = new[] { "add-capability", "install-to", "install-type", "Install-To", "Write-out", "read-only", "test-case", "out-of", "use-case", "use-case", "out-of", "Request-Monitor", "read-to", "read-from", "read-only", "Select-Alkami",/*Used as demo files when generating a module.*/"Get-HelloWorld", "Get-HelloWorldInternal", /*Two aliases that are harder to revert than I expected*/"New-AlkamiWebAppPool", "Get-AlkamiWebAppPool","new-relic","open-block","exit-condition" }; static List excludeNames = new List { "VariableDeclarations", "ConfigurationValues" }; const string CarbonModuleName = "Carbon"; const string WebAdministrationModuleName = "WebAdministration"; const string WindowsModuleName = "Generic Windows"; const string AwsModuleName = "AWS"; const string CloudbaseModuleName = "Cloudbase"; const string RedisModuleName = "Redis"; const string ServiceFabricModuleName = "ServiceFabric"; const string IgnoredFunctionsModuleName = "ignore anything with this module name"; #endregion static decls public static IEnumerable GetFunctionDefinitionsFromModule(DirectoryInfo directoryInfo, ModuleDefinition module, Regex regex) { var functionDefinitions = new List(); var publicFiles = directoryInfo.GetDirectories("Public").FirstOrDefault(); if (publicFiles != null) { foreach (var file in publicFiles.GetFiles("*.ps1")) { var filename = Path.GetFileNameWithoutExtension(file.FullName); if ( !(filename.EndsWith(".tests", StringComparison.InvariantCultureIgnoreCase) || filename.EndsWith(".test", StringComparison.InvariantCultureIgnoreCase)) && filename.IndexOf("-") > 1 && verbs.Contains(filename.Split('-')[0]) ) { var referencedFunctions = regex.Matches(File.ReadAllText(file.FullName)).OfType().SelectMany(m => m.Captures.OfType().ToArray().Select(x => x.Value)).Distinct().Where(x => x.ToLowerInvariant() != filename.ToLowerInvariant()); var functionDefinition = new ModuleFunctionDefinition(filename, module, referencedFunctions); functionDefinitions.Add(functionDefinition); } else { if ( !(filename.EndsWith(".tests", StringComparison.InvariantCultureIgnoreCase) || filename.EndsWith(".test", StringComparison.InvariantCultureIgnoreCase)) && !excludeNames.Contains(filename) ) { Console.WriteLine(string.Format("Did not match [{0}] as a valid filename.", file.Name)); } } } } var privateFiles = directoryInfo.GetDirectories("Private").FirstOrDefault(); if (privateFiles != null) { foreach (var file in privateFiles.GetFiles("*.ps1")) { var filename = Path.GetFileNameWithoutExtension(file.FullName); if ( !(filename.EndsWith(".tests", StringComparison.InvariantCultureIgnoreCase) || filename.EndsWith(".test", StringComparison.InvariantCultureIgnoreCase)) && filename.IndexOf("-") > 1 && verbs.Contains(filename.Split('-')[0])) { var referencedFunctions = regex.Matches(File.ReadAllText(file.FullName)).OfType().SelectMany(m => m.Captures.OfType().ToArray().Select(x => x.Value)).Distinct(); var functionDefinition = new ModuleFunctionDefinition(filename, module, referencedFunctions) { IsPrivate = true }; functionDefinitions.Add(functionDefinition); } else { if ( !(filename.EndsWith(".tests", StringComparison.InvariantCultureIgnoreCase) || filename.EndsWith(".test", StringComparison.InvariantCultureIgnoreCase)) && !excludeNames.Contains(filename) ) { Console.WriteLine(string.Format("Did not match [{0}] as a valid filename.", file.Name)); } } } } return functionDefinitions; } public static bool DoIt(string searchPath, bool showObviousCycles = false) { var matchVerbsString = string.Join("|", verbs); var matchString = string.Format("({0})-\\w+",matchVerbsString); var regex = new Regex(matchString, RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase); var allFoundFunctions = new List(); var allModules = new List(); #region pre-load ServiceFabric for reference var sf = new ModuleDefinition(ServiceFabricModuleName) { IsStub = true, IsBase = true }; foreach (var function in serviceFabricFunctions) { var fd = new ModuleFunctionDefinition(function, sf); sf.AddFunction(fd); allFoundFunctions.Add(fd); } #endregion pre-load Carbon for reference #region pre-load AWS for reference var aws = new ModuleDefinition(AwsModuleName) { IsStub = true, IsBase = true }; foreach (var function in awsFunctions) { var fd = new ModuleFunctionDefinition(function, aws); aws.AddFunction(fd); allFoundFunctions.Add(fd); } #endregion pre-load AWS for reference #region pre-load Carbon for reference var carbon = new ModuleDefinition(CarbonModuleName) { IsBase = true }; foreach (var function in carbonFunctions) { var fd = new ModuleFunctionDefinition(function, carbon); carbon.AddFunction(fd); allFoundFunctions.Add(fd); } #endregion pre-load Carbon for reference #region pre-load WebAdministration for reference var webAdministration = new ModuleDefinition(WebAdministrationModuleName) { IsBase = true }; foreach (var function in webAdministrationFunctions) { var fd = new ModuleFunctionDefinition(function, webAdministration); webAdministration.AddFunction(fd); allFoundFunctions.Add(fd); } #endregion pre-load WebAdministration for reference #region pre-load Windows for reference var windows = new ModuleDefinition(WindowsModuleName) { IsStub = true, IsBase = true }; foreach (var function in windowsFunctions) { var fd = new ModuleFunctionDefinition(function, windows); windows.AddFunction(fd); allFoundFunctions.Add(fd); } #endregion pre-load Windows for reference #region pre-load ignored functions for reference var ignored = new ModuleDefinition(IgnoredFunctionsModuleName) { IsStub = true, IsBase = true }; foreach (var function in ignoreRandomPhrases) { var fd = new ModuleFunctionDefinition(function, ignored); ignored.AddFunction(fd); allFoundFunctions.Add(fd); } #endregion pre-load Ignored functions for reference #region pre-load cloudbase for reference var cloudbase = new ModuleDefinition(CloudbaseModuleName) { IsStub = true, IsBase = true }; foreach (var function in cloudbase_powershell_yaml) { var fd = new ModuleFunctionDefinition(function, cloudbase); windows.AddFunction(fd); allFoundFunctions.Add(fd); } #endregion pre-load cloudbase for reference #region pre-load redis for reference var redis = new ModuleDefinition(RedisModuleName) { IsStub = true, IsBase = true }; foreach (var function in redisFunctions) { var fd = new ModuleFunctionDefinition(function, redis); aws.AddFunction(fd); allFoundFunctions.Add(fd); } #endregion pre-load redis for reference var modules = new DirectoryInfo(searchPath).GetFiles("*.psd1", SearchOption.AllDirectories); foreach (var module in modules) { var moduleName = Path.GetFileNameWithoutExtension(module.FullName); var isCsharp = false; if (module.Directory.GetFiles("*.csproj").Any()) { Console.WriteLine(string.Format("Found a CS Project for {0}",moduleName)); isCsharp = true; } var moduleDefinition = new ModuleDefinition(moduleName) { IsCsharp = isCsharp }; var functionDefinitions = GetFunctionDefinitionsFromModule(module.Directory, moduleDefinition, regex); moduleDefinition.AddFunctions(functionDefinitions); allFoundFunctions.AddRange(functionDefinitions); allModules.Add(moduleDefinition); } // Now that all the modules have been parsed and we have all the function definitions, we need to do something with the functions // Let's parse the functions to find all the places they are used, and see what that web looks like. // So basically, foreach function find modules they need to function. // There may be more than one function defined in a given module, example: Get-Certificate in carbon and alkami.ops.certificates Dictionary refDic = new Dictionary(); foreach (var function in allFoundFunctions) { if (!refDic.ContainsKey(function.Name.ToLower())) { refDic.Add(function.Name.ToLower(), function); } } foreach (var module in allModules) { foreach (var function in module.ModuleFunctionDefinitions) { foreach (var name in function.ReferencedFunctions) { if (function.ReferencedFunctions.Contains(name) && function.Name != name) { try { refDic[name.ToLower()].Add(function, module); if (!function.MyFunctions.Contains(refDic[name.ToLower()])) { function.MyFunctions.Add(refDic[name.ToLower()]); } } catch (Exception) { Console.WriteLine(string.Format("Could not find a parent-module for {0} in {1}",name,function.Name)); } } } } } Console.WriteLine(""); Console.WriteLine("======================"); Console.WriteLine(""); var shouldThrow = false; foreach (var module in allModules.Where(x => !x.IsStub)) { if (module.RelatedModules.Where(x => !x.IsStub).Any()) { Console.WriteLine(string.Format("{0} uses",module.Name)); foreach (var subModule in module.RelatedModules.Where(x => !x.IsStub)) { var isWrongOrder = (module.IsBase && !subModule.IsBase); var isObviousCycle = subModule.RelatedModules.Contains(module); if (isWrongOrder) { Console.WriteLine(string.Format(" * {0} - WARNING - SOMETHING REQUIRES A HIGHER-ORDER-FUNCTION", subModule.Name)); var exceptions = subModule.ModuleFunctionDefinitions.Where(x => x.ReferencedBy.Where(y => y.Module == module).Any()).Select(x => new { Name = x.Name, Where = x.ReferencedBy.Where(t => t.Module == module).Select(t => t.Name).ToArray() }); foreach (var exception in exceptions) { foreach (var functionName in exception.Where) { Console.WriteLine(string.Format(" * !! {0} calls {1}",functionName,exception.Name)); } } shouldThrow = true; } else if (isObviousCycle && showObviousCycles) { Console.WriteLine(string.Format(" * {0} - WARNING - OBVIOUS CYCLE",subModule.Name)); var exceptions = subModule.ModuleFunctionDefinitions.Where(x => x.ReferencedBy.Where(y => y.Module == module).Any()).Select(x => new { Name = x.Name, Where = x.ReferencedBy.Where(t => t.Module == module).Select(t => t.Name).ToArray() }); foreach (var exception in exceptions) { foreach (var functionName in exception.Where) { Console.WriteLine(string.Format(" * !! {0} calls {1}",functionName,exception.Name)); } } shouldThrow = true; } else { Console.WriteLine(string.Format(" * {0}",subModule.Name)); } } } else { Console.WriteLine(string.Format("{0} doesn't have additional-module usage",module.Name)); } Console.WriteLine(""); } return (shouldThrow); } } public class ModuleDefinition { public string Name { get; set; } public List ModuleFunctionDefinitions { get; set; } public List RelatedModules { get; set; } public int Weight { get; set; } public bool IsCsharp { get; set; } /// /// This flag means we are ignoring this "module" as it is only for comparison purposes /// public bool IsStub { get; set; } /// /// This means it's Alkami.PowerShell.* or something like it /// public bool IsBase { get; set; } public ModuleDefinition() { ModuleFunctionDefinitions = new List(); RelatedModules = new List(); Weight = 0; } public ModuleDefinition(string name) { Name = name; ModuleFunctionDefinitions = new List(); RelatedModules = new List(); Weight = 0; IsBase = name.ToLower().StartsWith("Alkami.PowerShell".ToLower()); } public ModuleDefinition(string name, IEnumerable relatedModuleNames) { Name = name; ModuleFunctionDefinitions = new List(); RelatedModules = new List(); RelatedModules.AddRange(relatedModuleNames); Weight = 0; IsBase = name.ToLower().StartsWith("Alkami.PowerShell".ToLower()); } public ModuleDefinition AddFunction(ModuleFunctionDefinition functionDefinition) { ModuleFunctionDefinitions.Add(functionDefinition); return this; } public ModuleDefinition AddFunctions(IEnumerable functionDefinitions) { ModuleFunctionDefinitions.AddRange(functionDefinitions); return this; } public override bool Equals(Object obj) { //Check for null and compare run-time types. if ((obj == null) || !this.GetType().Equals(obj.GetType())) { return false; } else { ModuleDefinition moduleDefinition = (ModuleDefinition)obj; return Name == moduleDefinition.Name; } } public override int GetHashCode() { return Name.GetHashCode(); } public override string ToString() { return string.Format("ModuleDefintion: {0}",Name); } } public class FunctionDefinition { public string Name { get; set; } public ModuleDefinition Module { get; set; } public bool IsPrivate { get; set; } public FunctionDefinition() { } public FunctionDefinition(string name) { Name = name; } public FunctionDefinition(string name, ModuleDefinition module) { Name = name; Module = module; } public override bool Equals(Object obj) { //Check for null and compare run-time types. if ((obj == null) || !this.GetType().Equals(obj.GetType())) { return false; } else { FunctionDefinition functionDefinition = (FunctionDefinition)obj; return Name == functionDefinition.Name; } } public override int GetHashCode() { return Name.GetHashCode(); } public override string ToString() { return string.Format("ModuleFunctionDefinition: {0} - ModuleDefinition {1}",Name,Module.Name); } } public class ModuleFunctionDefinition : FunctionDefinition { public List ReferencedFunctions { get; set; } public ModuleFunctionDefinition() : this(null) { } public ModuleFunctionDefinition(string name) : this(name, null) { } public ModuleFunctionDefinition(string name, ModuleDefinition module) : this(name, module, null) { } public ModuleFunctionDefinition(string name, ModuleDefinition module, IEnumerable referencedFunctions) : base(name, module) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException("name"); if (module == null) throw new ArgumentNullException("module"); ReferencedFunctions = new List(); if (referencedFunctions != null) { ReferencedFunctions.AddRange(referencedFunctions); } ReferencedBy = new List(); ReferencedIn = new List(); MyFunctions = new List(); } public FunctionDefinition Add(string referencedFunction) { ReferencedFunctions.Add(referencedFunction); return this; } public override bool Equals(Object obj) { //Check for null and compare run-time types. if ((obj == null) || !this.GetType().Equals(obj.GetType())) { return false; } else { FunctionDefinition functionDefinition = (FunctionDefinition)obj; return Name == functionDefinition.Name; } } public override int GetHashCode() { return Name.GetHashCode(); } public override string ToString() { return string.Format("ModuleFunctionDefinition: {0} - ModuleDefinition {1}",Name,Module.Name); } public void Add(ModuleFunctionDefinition functionDefinition, ModuleDefinition module) { if (!ReferencedBy.Contains(functionDefinition)) { ReferencedBy.Add(functionDefinition); } if (!ReferencedIn.Contains(module)) { ReferencedIn.Add(module); } if (Module != module && !module.RelatedModules.Contains(Module)) { module.RelatedModules.Add(Module); } } // These are the functions that reference me public List ReferencedBy { get; set; } // These are the functions that I reference public List ReferencedIn { get; set; } public List MyFunctions { get; set; } } "@; Write-Host "testing solution" Add-Type -TypeDefinition $cSharpCode; $result = [ModuleChecker]::DoIt($FolderPath, $ShowObviousCycles) if ($result) { if ($FailBuild) { throw "Failed processing, check output for bad module definitions" } else { Write-Warning "Failed processing, check output for bad module definitions" } } }