Skip to content

Commit 9328421

Browse files
authored
Merge pull request #289 from Azure/development
Release version 0.3.1
2 parents 76c13d3 + 49b5ccf commit 9328421

File tree

5 files changed

+108
-30
lines changed

5 files changed

+108
-30
lines changed

src/Analyzer.Cli.FunctionalTests/CommandLineParserTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public void AnalyzeTemplate_IncludesOrNotNonSecurityRules_ReturnsExpectedExitCod
102102
[TestMethod]
103103
public void AnalyzeDirectory_ValidInputValues_AnalyzesExpectedNumberOfFiles()
104104
{
105-
var args = new string[] { "analyze-directory", Directory.GetCurrentDirectory() };
105+
var args = new string[] { "analyze-directory", Path.Combine(Directory.GetCurrentDirectory(), "Tests") };
106106

107107
using StringWriter outputWriter = new();
108108
Console.SetOut(outputWriter);

src/Analyzer.PowerShellRuleEngine/PowerShellRuleEngine.cs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
using System;
55
using System.Collections.Generic;
66
using System.IO;
7+
using System.Management.Automation;
8+
using System.Management.Automation.Runspaces;
79
using Microsoft.Azure.Templates.Analyzer.Types;
810
using Microsoft.Azure.Templates.Analyzer.Utilities;
911
using Microsoft.Extensions.Logging;
1012
using Newtonsoft.Json.Linq;
1113
using PSRule.Configuration;
1214
using PSRule.Pipeline;
1315
using PSRule.Rules;
16+
using Powershell = System.Management.Automation.PowerShell; // There's a conflict between this class name and a namespace
1417

1518
namespace Microsoft.Azure.Templates.Analyzer.RuleEngines.PowerShellEngine
1619
{
@@ -38,6 +41,55 @@ public PowerShellRuleEngine(bool includeNonSecurityRules, ILogger logger = null)
3841
{
3942
this.includeNonSecurityRules = includeNonSecurityRules;
4043
this.logger = logger;
44+
45+
// We need to unblock the PowerShell scripts on Windows to allow them to run
46+
// If a script is not unblocked, even if it's signed, PowerShell prompts for confirmation before executing
47+
// This prompting would throw an exception, because there's no interaction with a user that would allow for confirmation
48+
if (Platform.IsWindows)
49+
{
50+
try
51+
{
52+
// There are 2 different 'Default' functions available:
53+
// https://docs.microsoft.com/en-us/powershell/scripting/developer/hosting/creating-an-initialsessionstate?view=powershell-7.2
54+
//
55+
// CreateDefault has a dependency on Microsoft.Management.Infrastructure.dll, which is missing when publishing for 'win-x64',
56+
// and PowerShell throws an exception creating the InitialSessionState.
57+
//
58+
// CreateDefault2 does NOT have this dependency.
59+
// Notably, Microsoft.Management.Infrastructure.dll is available when publishing for specific Windows versions (such as win7-x64),
60+
// but since this libary is not needed in our usage of PowerShell, we can eliminate the dependency.
61+
var initialState = InitialSessionState.CreateDefault2();
62+
63+
// Ensure we can execute the signed bundled scripts
64+
// This sets the policy at the Process scope
65+
initialState.ExecutionPolicy = PowerShell.ExecutionPolicy.RemoteSigned;
66+
67+
var powershell = Powershell.Create(initialState);
68+
69+
powershell
70+
.AddCommand("Get-ChildItem")
71+
.AddParameter("Path", Path.Combine(AppContext.BaseDirectory, "Modules", "PSRule.Rules.Azure"))
72+
.AddParameter("Recurse")
73+
.AddParameter("Filter", "*.ps1")
74+
.AddCommand("Unblock-File")
75+
.Invoke();
76+
77+
if (powershell.HadErrors)
78+
{
79+
this.logger?.LogError("There was an error unblocking the PowerShell scripts");
80+
81+
foreach (var error in powershell.Streams.Error)
82+
{
83+
this.logger?.LogError(error.ToString());
84+
}
85+
}
86+
}
87+
catch(Exception exception)
88+
{
89+
this.logger?.LogError(exception, "There was an exception while unblocking the PowerShell scripts");
90+
}
91+
92+
}
4193
}
4294

4395
/// <summary>
@@ -98,17 +150,8 @@ public IEnumerable<IEvaluation> AnalyzeTemplate(TemplateContext templateContext)
98150
NotProcessedWarning = false,
99151

100152
// PSRule internally creates a PowerShell initial state with InitialSessionState.CreateDefault().
101-
// There are 2 different 'Default' functions available:
102-
// https://docs.microsoft.com/en-us/powershell/scripting/developer/hosting/creating-an-initialsessionstate?view=powershell-7.2
103-
//
104-
// CreateDefault has a dependency on Microsoft.Management.Infrastructure.dll, which is missing when publishing for 'win-x64',
105-
// and PowerShell throws an exception creating the InitialSessionState.
106-
//
107-
// CreateDefault2 does NOT have this dependency.
108153
// SessionState.Minimal causes PSRule to use CreateDefault2 instead of CreateDefault.
109-
// Notably, Microsoft.Management.Infrastructure.dll is available when publishing for specific Windows versions (such as win7-x64),
110-
// but since this libary is not needed in our usage of PowerShell, we can eliminate the dependency.
111-
InitialSessionState = SessionState.Minimal
154+
InitialSessionState = PSRule.Configuration.SessionState.Minimal
112155
}
113156
};
114157
var resources = templateContext.ExpandedTemplate.InsensitiveToken("resources").Values<JObject>();

src/Analyzer.TemplateProcessor.UnitTests/ArmTemplateProcessorTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1114,7 +1114,7 @@ public void ProcessTemplate_ValidTemplateUsingManagementGroupFunction_ProcessTem
11141114

11151115
JToken template = armTemplateProcessor.ProcessTemplate();
11161116

1117-
Assert.AreEqual("/providers/Microsoft.Management/managementGroups/examplemg1", template["resources"][0]["properties"]["details"]["parent"]["id"]);
1117+
Assert.AreEqual("/providers/Microsoft.Management/managementGroups/placeholderManagementGroup", template["resources"][0]["properties"]["details"]["parent"]["id"]);
11181118
}
11191119

11201120
private string GenerateTemplateWithOutputs(string outputValue)

src/Analyzer.TemplateProcessor/PlaceholderInputGenerator.cs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -104,16 +104,16 @@ internal static InsensitiveDictionary<JToken> GeneratePlaceholderDeploymentMetad
104104
{
105105
var deployment = JObject.Parse(@"
106106
{
107-
""name"": ""deploymentname"",
108-
""type"": ""deploymenttype"",
107+
""name"": ""placeholderDeploymentName"",
108+
""type"": ""placeholderDeploymentType"",
109109
""location"": ""westus2"",
110-
""id"": ""/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroupName"",
110+
""id"": ""/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/placeholderResourceGroup"",
111111
""properties"": {
112112
""templateLink"": {
113113
""uri"": ""https://deploymenturi"",
114114
""contentVersion"": ""0.0"",
115115
""metadata"": {
116-
""metadata"": ""deploymentmetadata""
116+
""metadata"": ""placeholderDeploymentMetadata""
117117
}
118118
}
119119
}
@@ -160,40 +160,62 @@ internal static InsensitiveDictionary<JToken> GeneratePlaceholderDeploymentMetad
160160
}
161161
}");
162162

163-
var managementGroupInfo = JObject.Parse(@"
163+
var managementGroup = JObject.Parse(@"
164164
{
165-
""id"": ""/providers/Microsoft.Management/managementGroups/examplemg1"",
166-
""name"": ""examplemg1"",
165+
""id"": ""/providers/Microsoft.Management/managementGroups/placeholderManagementGroup"",
166+
""name"": ""placeholderManagementGroup"",
167167
""properties"": {
168168
""details"": {
169169
""parent"": {
170-
""displayName"": ""Tenant Root Group"",
170+
""displayName"": ""Placeholder Tenant Root Group"",
171171
""id"": ""/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000"",
172172
""name"": ""00000000-0000-0000-0000-000000000000""
173173
},
174174
""updatedBy"": ""00000000-0000-0000-0000-000000000000"",
175175
""updatedTime"": ""2020-07-23T21:05:52.661306Z"",
176176
""version"": ""1""
177177
},
178-
""displayName"": ""Example MG 1"",
178+
""displayName"": ""Placeholder Management Group"",
179179
""tenantId"": ""00000000-0000-0000-0000-000000000000""
180180
},
181181
""type"": ""/providers/Microsoft.Management/managementGroups""
182182
}");
183183

184+
var subscription = JObject.Parse(@"
185+
{
186+
""id"": ""/subscriptions/00000000-0000-0000-0000-000000000000"",
187+
""subscriptionId"": ""00000000-0000-0000-0000-000000000000"",
188+
""tenantId"": ""00000000-0000-0000-0000-000000000000"",
189+
""displayName"": ""Placeholder Subscription Name""
190+
}");
191+
192+
var resourceGroup = JObject.Parse(@"
193+
{
194+
""id"": ""/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/placeholderResourceGroup"",
195+
""name"": ""placeholderResourceGroup"",
196+
""type"":""Microsoft.Resources/resourceGroups"",
197+
""location"": ""westus2"",
198+
""properties"": {
199+
""provisioningState"": ""Succeeded""
200+
}
201+
}");
202+
203+
var tenant = JObject.Parse(@"
204+
{
205+
""countryCode"": ""US"",
206+
""displayName"": ""Placeholder Tenant"",
207+
""id"": ""/tenants/00000000-0000-0000-0000-000000000000"",
208+
""tenantId"": ""00000000-0000-0000-0000-000000000000""
209+
}");
210+
184211
var metadata = new InsensitiveDictionary<JToken>
185212
{
186-
{ "subscription", new JObject(
187-
new JProperty("id", "/subscriptions/00000000-0000-0000-0000-000000000000"),
188-
new JProperty("subscriptionId", "00000000-0000-0000-0000-000000000000"),
189-
new JProperty("tenantId", "00000000-0000-0000-0000-000000000000")) },
190-
{ "resourceGroup", new JObject(
191-
new JProperty("id", "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroupName"),
192-
new JProperty("location", "westus2"),
193-
new JProperty("name", "resource-group")) },
194-
{ "managementGroup", managementGroupInfo },
213+
{ "subscription", subscription },
214+
{ "resourceGroup", resourceGroup },
215+
{ "managementGroup", managementGroup },
195216
{ "deployment", deployment },
196217
{ "tenantId", "00000000-0000-0000-0000-000000000000" },
218+
{ "tenant", tenant },
197219
{ "providers", providers },
198220
{ "environment", environment }
199221
};

src/Directory.Build.targets

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,17 @@
44
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
55
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
66
</PropertyGroup>
7+
8+
<!-- Move platform-specific runtime modules directly into the publish directory -->
9+
<Target Name="UpdatePSRuntimeModules" AfterTargets="Publish">
10+
<PropertyGroup>
11+
<OSDirectory Condition="'$(OS)' == 'Unix'">unix</OSDirectory>
12+
<OSDirectory Condition="'$(OS)' != 'Unix'">win</OSDirectory>
13+
</PropertyGroup>
14+
<ItemGroup>
15+
<Modules Include="$(PublishDir)\runtimes\$(OSDirectory)\lib\$(TargetFramework)\Modules\**\*" />
16+
</ItemGroup>
17+
<Move SourceFiles="@(Modules)" DestinationFolder="$(PublishDir)\Modules\%(RecursiveDir)" />
18+
<RemoveDir Directories="$(PublishDir)\runtimes" />
19+
</Target>
720
</Project>

0 commit comments

Comments
 (0)