Skip to content

Commit 7d850bb

Browse files
rjmholtJamesWTruher
authored andcommitted
New PowerShell compatibility rules (#1133)
* Add compatibilty rule serialization types * Move compatibility checking code into submodule * Create module manifest, change module base dir name * Move module to new file, change namespaces * Add submodule binplace dir to .gitignore * Delete binary files * Fix up lsb info function * Fixup module, correct names and namespaces * Remove debugger wait * Improve architecture handling * Clean up serialization API * Improve module filtering * Partial work on query API * Add more query types * Update query API, move enums to common * Add assembly name to type accelerator dictionary * Add reference to compatibility project in pssa * Add new command compatibility rule * Add deep clone, basic rule implementation * Make profiles multi-platform * Fix Platform type name usage * Add intersection logic * Change to ICloneable, add some union functionality * More union implementation * Finish union logic * Add combinator methods * Fix profile creation, add combinator cmdlet * Fix intersection logic, module versioning * Fix various NREs, try to improve profile combination * Replace IDictionary with JsonDictionary * Change build target properly * Fix broken namespace and build version * Get output from intersection command * TODO about intersection * Fix version intersections * Add profiles to the committed assets * Add function to generate any_profile config * Revert net452 change in order to build * Make profiles single-platform, enable multiple targets * Hook rule into testing * Fix string resources * Hook cross compat up to first test * Add custom diagnostic type for compatibility checking * Begin fixing case sensitivity * Fix case sensitivity in profile union * Fix platform property, make test pass * Add singleton for performance, change tests to test cases * Add cache clear method for profile loader * enable building on non-Windows to not target .Net Framework by default (#1) * Make PSScriptAnalyzer build independent of CrossCompatibility build * Fix dll path issue in psm1 * Add ubuntu 18.04 profiles * Fix root module, fix type names, powershell version may be string * Make script compatible with PSv3 * Fix v3 compat, add union profile name, begin version work * Add PowerShellVersion class * Change PowerShell json to new version type, add test build * Add documentation for UseCompatibleCmdlets2 * Remove PS from configuration example * Fix versions + build merge problem, start typename fix * Serialize type names correctly * Make function exports explicit * Fix psd1, add type name normalization functions * Fix name normalization, add type query logic, genericize compatibility rules, add skeleton for type compatibility rule * Fix type query building bug, rename command compat rule, begin type compat rule * Build out type compatibility check rule * Use simple typename expansion * Remove unused test assets, add scaffold for type tests, change platform naming to include dotnet details * Fix alias glitch, add native commands, move type conversion api * Add better profiles, add native command tracking, fix union and build * Add union profile, move AzF profile out of folder * Move analysis exception to new file/namespace * Add -Clean to build script * Use new ending for profile extension * Use new structure for native commands * Add more command tests, fix GAC ignorance in profiler module * Fix bugs in profile script, add validation function * Fix profiler bugs, remove old profiles * Ignore lack of profile dir * Omit edition on lower PS versions * Add new profiles, remove intersection logic, fix unions * Add IDs to profiles for later union autogeneration * Make profile loader more threadsafe * Use net452-compatible hashset logic * Fudge over type compilation bug * Add types tests, fix command param parsing, fix attribute parsing * Update documentation, add types test * Add copyright headers * Add some doc comments - more to come * Add simple syntax compatibility rule * Add workflow checking * Remove parallel and sequence linting * update .net core version in README.md to match global.json * The engine project does not need a reference to the crosscompat project since the Rules project has this already * Remove example file * Fix safe expression evaluation in settings parser * Remove bad debug code * Update language in gitignore * Add proper resource strings * Make tests pass * Remove unneeded bits * Add MEF attributes * Fix executable name problem * Use correct report summary switch * Fix test bugs * Tweaks to failing tests * Add documentation comments to C# * Remove violations error write in test * Add debug to csproj const properties * Simplify build macros in the hope that they work now * Make profile cache case insensitive * Add PSV3/4 flags to debug configurations * Improve new-object correction syntax * Add tests for and fix up GetSafeValue implementation * Move to autogenerated union files * Quote paths for testing, add exception to alias tests, remove unused regex * Add command parameter and static type member checking * Enforce readonly nature of platform object * Fix bugs in code and test * Write union profile out on creation * Add ignore settings for command and type compatibility rules * Add more testing, fix bugs, renew profiles * Detect dynamic method invocation for ps3 compatibility * Move from PLINQ to tasks * Take out nonfix in command rule, fix build script syntax problem * Fix profile union, type compat bugs, add type compat tests * Add script test for compatible commands * Add tests for compatible syntax rule * Add repo-facing tests for UseCompatibleSyntax * Temp test to see ubuntu problem * Fix ubuntu date alias test * Fix test failure in PSv3/4 * Make new error messages into resource strings * Add newtonsoft.json manually in old old powershell versions * Filter diagnostics to omit parse errors * Fix last PSv3/4 specific test * Use better compile-time macro * Get rid of verbose logging of activator instantiation * Turn LINQ into lazy static methods * Fix NRE in types, move command query tables to lazy methods * Add CrossCompatibility to AppVeyor build and test * Prevent trying to reload CrossCompatibility.dll * Add Windows SKU enum to platform query object * Fix problems with CC module in AppVeyor path * More probing * Fix CC build condition * Add FX to build script params * Attempt to fix Dll binplace issue * Fix typename logic * Fix EOL in files * Remove unused LINQ calls * Address some of @JamesWTruher's feedback * Better way to get common parameters * Address more of @JamesWTruher's feedback * Address @bergmeister's add-type feedback * Address pipe usage, nasty foreach * Profiles bundled as a ZIP file * Ignore zip type in build file * Ensure zip functions are present * Change name of cross compat assembly * Add cross compat asm to signing * Address more of @JamesWTruher's feedback * Fix build path bug * Make some profiles optional, improve compat rule docs * Add documentation * Remove defunct anyplatform name * Add exclusion parameters to cc module * Add parameter documentation * Fix automatic variable detection * Add explicit default case * Fix tests for fewer rules * Fix type compat test profile bugs * Fix compatibility module bug * Add path exclusions to module * Fix linux pscustomobject problem * Fix profile module bugs, update profiles * Update documentation for profile names * Rename module and sign * Fix build name bug * Upgrade docket .NET version * Ignore clean error * Add verbose message to release script * Verbose hack * Remove verbose * Tweak out copy * Fix signing xml * Fix signing XML * Correct framework signing to net452 * Remove AuthenticodeDual * Update signing for PSCompatibilityAnalyzer * Update VSCode search exclusion for profiles * Fix loading problem in PowerShell 5 * Fix Add-Type Newtonsoft in PS 5 * Add missing copyright headers * Add other copyright headers
1 parent cfeb7d5 commit 7d850bb

File tree

119 files changed

+11679
-249
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

119 files changed

+11679
-249
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ bld/
2525
# Visual Studo 2015 cache/options directory
2626
.vs/
2727

28+
# VSCode configuration directory
29+
.vscode/
30+
2831
# MSTest test Results
2932
[Tt]est[Rr]esult*/
3033
[Bb]uild[Ll]og.*
@@ -212,3 +215,6 @@ PSScriptAnalyzer/
212215

213216
# Test result file
214217
TestResults.xml
218+
219+
# PSCompatibilityAnalyzer module
220+
PSCompatibilityAnalyzer/out/

.vscode/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,11 @@
44
"powershell.codeFormatting.preset": "Allman",
55
"[powershell]": {
66
"files.trimTrailingWhitespace": true
7+
},
8+
"search.exclude": {
9+
"**/node_modules": true,
10+
"**/bower_components": true,
11+
"/PSCompatibilityAnalyzer/profiles": true,
12+
"/PSCompatibilityAnalyzer/optional_profiles": true
713
}
814
}

Engine/Engine.csproj

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
<ItemGroup Condition="'$(TargetFramework)' == 'net452' AND '$(Configuration)' != 'PSV3Release'">
7777
<PackageReference Include="Microsoft.PowerShell.5.ReferenceAssemblies" Version="1.1.0" />
7878
</ItemGroup>
79-
79+
8080
<PropertyGroup Condition=" '$(Configuration)' == 'PSV3Release' ">
8181
<DefineConstants>$(DefineConstants);PSV3</DefineConstants>
8282
</PropertyGroup>
@@ -85,4 +85,12 @@
8585
<DefineConstants>$(DefineConstants);PSV3;PSV4</DefineConstants>
8686
</PropertyGroup>
8787

88+
<PropertyGroup Condition=" '$(Configuration)' == 'PSV3Debug' ">
89+
<DefineConstants>$(DefineConstants);PSV3</DefineConstants>
90+
</PropertyGroup>
91+
92+
<PropertyGroup Condition=" '$(Configuration)' == 'PSV4Debug' ">
93+
<DefineConstants>$(DefineConstants);PSV3;PSV4</DefineConstants>
94+
</PropertyGroup>
95+
8896
</Project>

Engine/Generic/ConfigurableRule.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Management.Automation;
67
using System.Management.Automation.Language;
78
using System.Reflection;
89

@@ -118,6 +119,13 @@ private void SetDefaultValues()
118119

119120
private void SetValue(PropertyInfo property, object value)
120121
{
122+
if (IsArray(property.PropertyType, out Type elementType))
123+
{
124+
object newArray = LanguagePrimitives.ConvertTo(value, elementType.MakeArrayType());
125+
property.SetValue(this, newArray);
126+
return;
127+
}
128+
121129
// TODO Check if type is convertible
122130
property.SetValue(this, Convert.ChangeType(value, property.PropertyType));
123131
}
@@ -145,5 +153,17 @@ private Object GetDefaultValue(PropertyInfo property)
145153

146154
return ((ConfigurableRulePropertyAttribute)attr).DefaultValue;
147155
}
156+
157+
private static bool IsArray(Type propertyType, out Type elementType)
158+
{
159+
if (propertyType.IsArray)
160+
{
161+
elementType = propertyType.GetElementType();
162+
return true;
163+
}
164+
165+
elementType = null;
166+
return false;
167+
}
148168
}
149169
}

Engine/Generic/ConfigurableRulePropertyAttribute.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic
1111
[AttributeUsage(AttributeTargets.Property)]
1212
public class ConfigurableRulePropertyAttribute : Attribute
1313
{
14+
// TODO: Remove this parameter or make it optional.
15+
// Properties already have a way to specify default values in C#.
16+
// Having this prevents using null (which may be legitimate)
17+
// or values from other assemblies, and overrides the constructor,
18+
// which just makes life harder.
19+
1420
/// <summary>
1521
/// Default value of the property that the attribute decorates.
1622
/// </summary>
@@ -22,6 +28,7 @@ public class ConfigurableRulePropertyAttribute : Attribute
2228
/// <param name="defaultValue"></param>
2329
public ConfigurableRulePropertyAttribute(object defaultValue)
2430
{
31+
// TODO: null is a legitimate value and should be allowed.
2532
if (defaultValue == null)
2633
{
2734
throw new ArgumentNullException(nameof(defaultValue), Strings.ConfigurableScriptRuleNRE);

Engine/PSScriptAnalyzer.psm1

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ if (($PSVersionTable.Keys -contains "PSEdition") -and ($PSVersionTable.PSEdition
1717
throw "Minimum supported version of PSScriptAnalyzer for PowerShell Core is 6.0.2 but current version is '$($PSVersionTable.PSVersion)'. Please update PowerShell Core."
1818
}
1919
}
20-
else {
21-
if ($PSVersionTable.PSVersion.Major -eq 3) {
22-
$binaryModuleRoot = Join-Path -Path $PSModuleRoot -ChildPath 'PSv3'
23-
}
24-
elseif ($PSVersionTable.PSVersion.Major -eq 4) {
25-
$binaryModuleRoot = Join-Path -Path $PSModuleRoot -ChildPath 'PSv4'
26-
}
20+
elseif ($PSVersionTable.PSVersion.Major -eq 5) {
21+
# Without this, PSSA tries to load this from $PSHome
22+
Add-Type -Path "$PSScriptRoot/Newtonsoft.Json.dll"
23+
}
24+
elseif ($PSVersionTable.PSVersion.Major -le 4) {
25+
$binaryModuleRoot = Join-Path -Path $PSModuleRoot -ChildPath "PSv$($PSVersionTable.PSVersion.Major)"
26+
# Without this, PSSA tries to load this from $PSHome
27+
Add-Type -Path "$binaryModuleRoot/Newtonsoft.Json.dll"
2728
}
2829

2930
$binaryModulePath = Join-Path -Path $binaryModuleRoot -ChildPath 'Microsoft.Windows.PowerShell.ScriptAnalyzer.dll'

Engine/ScriptAnalyzer.cs

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -876,39 +876,37 @@ private IEnumerable<T> GetInterfaceImplementationsFromAssembly<T>() where T : cl
876876

877877
private IEnumerable<T> GetInterfaceImplementationsFromAssembly<T>(string ruleDllPath) where T : class
878878
{
879-
var fileName = Path.GetFileNameWithoutExtension(ruleDllPath);
879+
string fileName = Path.GetFileNameWithoutExtension(ruleDllPath);
880880
var assemblyName = new AssemblyName(fileName);
881881
outputWriter.WriteVerbose(string.Format("Loading Assembly:{0}", assemblyName.FullName));
882882

883-
var dll = Assembly.Load(assemblyName);
884-
var rules = new List<T>();
883+
Assembly dll = Assembly.Load(assemblyName);
884+
885885
if (dll == null)
886886
{
887887
outputWriter.WriteVerbose(string.Format("Cannot load {0}", ruleDllPath));
888-
return rules;
888+
return Enumerable.Empty<T>();
889889
}
890-
foreach (var type in dll.ExportedTypes)
890+
891+
var rules = new List<T>();
892+
foreach (Type type in dll.ExportedTypes)
891893
{
892-
var typeInfo = type.GetTypeInfo();
893-
if (!typeInfo.IsInterface
894-
&& !typeInfo.IsAbstract
895-
&& typeInfo.ImplementedInterfaces.Contains(typeof(T)))
894+
if (type.IsInterface
895+
|| type.IsAbstract
896+
|| !typeof(T).IsAssignableFrom(type))
897+
{
898+
continue;
899+
}
900+
901+
var rule = Activator.CreateInstance(type) as T;
902+
if (rule == null)
896903
{
897904
outputWriter.WriteVerbose(
898905
string.Format(
899-
"Creating Instance of {0}", type.Name));
900-
901-
var ruleObj = Activator.CreateInstance(type);
902-
T rule = ruleObj as T;
903-
if (rule == null)
904-
{
905-
outputWriter.WriteVerbose(
906-
string.Format(
907-
"Cannot cast instance of type {0} to {1}", type.Name, typeof(T).GetTypeInfo().Name));
908-
continue;
909-
}
910-
rules.Add(rule);
906+
"Cannot cast instance of type {0} to {1}", type.Name, typeof(T).GetTypeInfo().Name));
907+
continue;
911908
}
909+
rules.Add(rule);
912910
}
913911
return rules;
914912
}

0 commit comments

Comments
 (0)