12
12
13
13
namespace System . Management . Automation . Security
14
14
{
15
+ /// <summary>
16
+ /// System wide policy enforcement for a specific script file.
17
+ /// </summary>
18
+ public enum SystemScriptFileEnforcement
19
+ {
20
+ /// <summary>
21
+ /// No policy enforcement.
22
+ /// </summary>
23
+ None = 0 ,
24
+
25
+ /// <summary>
26
+ /// Script file is blocked from running.
27
+ /// </summary>
28
+ Block = 1 ,
29
+
30
+ /// <summary>
31
+ /// Script file is allowed to run without restrictions (FullLanguage mode).
32
+ /// </summary>
33
+ Allow = 2 ,
34
+
35
+ /// <summary>
36
+ /// Script file is allowed to run in ConstrainedLanguage mode only.
37
+ /// </summary>
38
+ AllowConstrained = 3
39
+ }
40
+
15
41
/// <summary>
16
42
/// How the policy is being enforced.
17
43
/// </summary>
@@ -71,6 +97,90 @@ public static SystemEnforcementMode GetSystemLockdownPolicy()
71
97
private static readonly object s_systemLockdownPolicyLock = new object ( ) ;
72
98
private static SystemEnforcementMode ? s_systemLockdownPolicy = null ;
73
99
private static bool s_allowDebugOverridePolicy = false ;
100
+ private static bool s_wldpCanExecuteAvailable = true ;
101
+
102
+ /// <summary>
103
+ /// Gets the system wide script file policy enforcement for an open file.
104
+ /// Based on system WDAC (Windows Defender Application Control) or AppLocker policies.
105
+ /// </summary>
106
+ /// <param name="filePath">Script file path for policy check.</param>
107
+ /// <param name="fileStream">FileStream object to script file path.</param>
108
+ /// <returns>Policy check result for script file.</returns>
109
+ public static SystemScriptFileEnforcement GetFilePolicyEnforcement (
110
+ string filePath ,
111
+ System . IO . FileStream fileStream )
112
+ {
113
+ SafeHandle fileHandle = fileStream . SafeFileHandle ;
114
+
115
+ // First check latest WDAC APIs if available.
116
+ if ( s_wldpCanExecuteAvailable )
117
+ {
118
+ try
119
+ {
120
+ string fileName = System . IO . Path . GetFileNameWithoutExtension ( filePath ) ;
121
+ string auditMsg = $ "PowerShell ExternalScriptInfo reading file: { fileName } ";
122
+
123
+ int hr = WldpNativeMethods . WldpCanExecuteFile (
124
+ host : PowerShellHost ,
125
+ options : WLDP_EXECUTION_EVALUATION_OPTIONS . WLDP_EXECUTION_EVALUATION_OPTION_NONE ,
126
+ fileHandle : fileHandle . DangerousGetHandle ( ) ,
127
+ auditInfo : auditMsg ,
128
+ result : out WLDP_EXECUTION_POLICY canExecuteResult ) ;
129
+
130
+ if ( hr >= 0 )
131
+ {
132
+ switch ( canExecuteResult )
133
+ {
134
+ case WLDP_EXECUTION_POLICY . WLDP_CAN_EXECUTE_ALLOWED :
135
+ return SystemScriptFileEnforcement . Allow ;
136
+
137
+ case WLDP_EXECUTION_POLICY . WLDP_CAN_EXECUTE_BLOCKED :
138
+ return SystemScriptFileEnforcement . Block ;
139
+
140
+ case WLDP_EXECUTION_POLICY . WLDP_CAN_EXECUTE_REQUIRE_SANDBOX :
141
+ return SystemScriptFileEnforcement . AllowConstrained ;
142
+
143
+ default :
144
+ // Fall through to legacy system policy checks.
145
+ System . Diagnostics . Debug . Assert ( false , $ "Unknown execution policy returned from WldCanExecute: { canExecuteResult } ") ;
146
+ break ;
147
+ }
148
+ }
149
+
150
+ // If HResult is unsuccessful (such as E_NOTIMPL (0x80004001)), fall through to legacy system checks.
151
+ }
152
+ catch ( DllNotFoundException )
153
+ {
154
+ // Fall back to legacy system policy checks.
155
+ s_wldpCanExecuteAvailable = false ;
156
+ }
157
+ catch ( EntryPointNotFoundException )
158
+ {
159
+ // Fall back to legacy system policy checks.
160
+ s_wldpCanExecuteAvailable = false ;
161
+ }
162
+ }
163
+
164
+ // Original (legacy) WDAC and AppLocker system checks.
165
+ if ( SystemPolicy . GetSystemLockdownPolicy ( ) != SystemEnforcementMode . None )
166
+ {
167
+ switch ( SystemPolicy . GetLockdownPolicy ( filePath , fileHandle ) )
168
+ {
169
+ case SystemEnforcementMode . Enforce :
170
+ return SystemScriptFileEnforcement . AllowConstrained ;
171
+
172
+ case SystemEnforcementMode . None :
173
+ case SystemEnforcementMode . Audit :
174
+ return SystemScriptFileEnforcement . Allow ;
175
+
176
+ default :
177
+ System . Diagnostics . Debug . Assert ( false , "GetFilePolicyEnforcement: Unknown SystemEnforcementMode." ) ;
178
+ return SystemScriptFileEnforcement . Block ;
179
+ }
180
+ }
181
+
182
+ return SystemScriptFileEnforcement . None ;
183
+ }
74
184
75
185
/// <summary>
76
186
/// Gets lockdown policy as applied to a file.
@@ -546,18 +656,66 @@ internal struct WLDP_HOST_INFORMATION
546
656
internal IntPtr hSource ;
547
657
}
548
658
659
+ /// <summary>
660
+ /// Options for WldpCanExecuteFile method.
661
+ /// </summary>
662
+ [ Flags ]
663
+ internal enum WLDP_EXECUTION_EVALUATION_OPTIONS
664
+ {
665
+ WLDP_EXECUTION_EVALUATION_OPTION_NONE = 0x0 ,
666
+ WLDP_EXECUTION_EVALUATION_OPTION_EXECUTE_IN_INTERACTIVE_SESSION = 0x1
667
+ }
668
+
669
+ /// <summary>
670
+ /// Results from WldpCanExecuteFile method.
671
+ /// </summary>
672
+ internal enum WLDP_EXECUTION_POLICY
673
+ {
674
+ WLDP_CAN_EXECUTE_BLOCKED = 0 ,
675
+ WLDP_CAN_EXECUTE_ALLOWED = 1 ,
676
+ WLDP_CAN_EXECUTE_REQUIRE_SANDBOX = 2
677
+ }
678
+
679
+ /// <summary>
680
+ /// Powershell Script Host.
681
+ /// </summary>
682
+ internal static readonly Guid PowerShellHost = new Guid ( "8E9AAA7C-198B-4879-AE41-A50D47AD6458" ) ;
683
+
549
684
/// <summary>
550
685
/// Native methods for dealing with the lockdown policy.
551
686
/// </summary>
552
687
internal static class WldpNativeMethods
553
688
{
689
+ /// <summary>
690
+ /// Returns a WLDP_EXECUTION_POLICY enum value indicating if and how a script file
691
+ /// should be executed.
692
+ /// </summary>
693
+ /// <param name="host">Host guid.</param>
694
+ /// <param name="options">Evaluation options.</param>
695
+ /// <param name="fileHandle">Evaluated file handle.</param>
696
+ /// <param name="auditInfo">Auditing information string.</param>
697
+ /// <param name="result">Evaluation result.</param>
698
+ /// <returns>HResult value.</returns>
699
+ [ DefaultDllImportSearchPathsAttribute ( DllImportSearchPath . System32 ) ]
700
+ [ DllImportAttribute ( "wldp.dll" , EntryPoint = "WldpCanExecuteFile" ) ]
701
+ internal static extern int WldpCanExecuteFile (
702
+ Guid host ,
703
+ WLDP_EXECUTION_EVALUATION_OPTIONS options ,
704
+ IntPtr fileHandle ,
705
+ [ MarshalAs ( UnmanagedType . LPWStr ) ]
706
+ string auditInfo ,
707
+ out WLDP_EXECUTION_POLICY result ) ;
708
+
554
709
/// Return Type: HRESULT->LONG->int
555
710
/// pHostInformation: PWLDP_HOST_INFORMATION->_WLDP_HOST_INFORMATION*
556
711
/// pdwLockdownState: PDWORD->DWORD*
557
712
/// dwFlags: DWORD->unsigned int
558
713
[ DefaultDllImportSearchPathsAttribute ( DllImportSearchPath . System32 ) ]
559
714
[ DllImportAttribute ( "wldp.dll" , EntryPoint = "WldpGetLockdownPolicy" ) ]
560
- internal static extern int WldpGetLockdownPolicy ( ref WLDP_HOST_INFORMATION pHostInformation , ref uint pdwLockdownState , uint dwFlags ) ;
715
+ internal static extern int WldpGetLockdownPolicy (
716
+ ref WLDP_HOST_INFORMATION pHostInformation ,
717
+ ref uint pdwLockdownState ,
718
+ uint dwFlags ) ;
561
719
562
720
/// Return Type: HRESULT->LONG->int
563
721
/// rclsid: IID*
@@ -566,7 +724,11 @@ internal static class WldpNativeMethods
566
724
/// dwFlags: DWORD->unsigned int
567
725
[ DefaultDllImportSearchPathsAttribute ( DllImportSearchPath . System32 ) ]
568
726
[ DllImportAttribute ( "wldp.dll" , EntryPoint = "WldpIsClassInApprovedList" ) ]
569
- internal static extern int WldpIsClassInApprovedList ( ref Guid rclsid , ref WLDP_HOST_INFORMATION pHostInformation , ref int ptIsApproved , uint dwFlags ) ;
727
+ internal static extern int WldpIsClassInApprovedList (
728
+ ref Guid rclsid ,
729
+ ref WLDP_HOST_INFORMATION pHostInformation ,
730
+ ref int ptIsApproved ,
731
+ uint dwFlags ) ;
570
732
571
733
[ DllImport ( "shell32.dll" , CharSet = CharSet . Unicode , SetLastError = true ) ]
572
734
internal static extern int SHGetKnownFolderPath (
0 commit comments