#PowerShell Constrained Language Mode

1 messages · Page 1 of 1 (latest)

valid pecan
#

Judging from the text you linked it seems you can only add dotnet types to the allow list.
Im not too familiar with wdac policy, what feature are you looking to use in constrained mode?

Tbh this seems to break most modules and scripts kind of like strictmode. 😬

valid pecan
#

Yea. Hm from the blog that the list is from seem to say as much.

Since Constrained Language is so limited, you will find that many of the approved scripts that you use for advanced systems management no longer work. The solution to this is simple: add these scripts (or more effectively: your code signing authority that signed them) to your Device Guard policy. This will allow your approved scripts to run in Full Language mode.

#

Blog post from 2017 😬

valid pecan
#

just took a quick look at your code, kinda seems like your just suppressing the errors with empty catch blocks.. so thats probably why your not seeing any issues with turning on strict mode,

& {
    Set-StrictMode -Version Latest
    try {
        if (-Not $foo) {
            throw 'rocks'
        }
    }
    catch {}
    if (-Not $bar) {
        'bar is not defined'
    }
}

also i saw alot of += which is pretty bad for performance, can see the recent discussion in #fringe for more information

#

do you have a C# background? kinda seems like it from your code, strongly typing every variable

#

👍

valid pecan
#

damn, thats quite an improvement, nice work!

valid pecan
#

if your after performance gains i would run Profiler, it will show the top offenders etc.
https://github.com/nohwnd/Profiler

but i did look over your code, some random thoughts.

New-Variable, avoid all the *-Variable commands, they make it so it cant be optimized.

using ::new() over New-Object

you dont need to [void] Generic.List (unlike ArrayList)

usually you dont need to use a generic list at all
assigning the loop will most likely be the fastest, ie
$Objects = foreach ($i in 1..10) { $i }
(there are some excellent benchmarks in fringe from the recent += improvement discussions.

i would change

 $null = Get-Item -Path "Registry::$($Item.Key)"
# If no error is thrown, the key exists
$KeyExists = $true

to

if (Test-Path -Path "Registry::$($Item.Key)") {
    # do stuff
}

it looks like you could probably get rid of most of your empty catch blocks with that approach.

the powershell.exe block could be reworked a bit..
by calling Get-WindowsCapability -Online once and saving it to a variable (instead of 7)
iirc that command is not super fast? could be an easy gain atleast

$cap = Get-WindowsCapability -Online
$cap | where { .. }

some personal preference stuff, not really performance thing.

i would probably skip using nested functions, makes it alot harder to read and follow the code imo.
also makes it harder to test.
nested functions can be fine but those are a bit large for that.

maybe use splatting to reduce code width, also makes it more readable.

#

just saw the preloader, not a security expert but those constant variables are not tamper proof, though unlikely it is possible to modify them with reflection.
#powershell-help message

valid pecan
#

Yea, click the powershell help link. That will take you to an example 😀

#

I actually think you said tamper resistant and I just worded it wrong. Resistant is correct

#

I dont know of a way no, might be possible in c# but not sure.

valid pecan
#

You need to save it to a variable.
$trace = Trace-Script -Scriptblock ...

#

Its a fairly large object returned with lots of different format views etc

valid pecan
#

Weird, is there anything in $trace.top50selfduration?
Not sure how it handles threadjobs/runspaces. Imagine that can be a challenge to trace

#

Hes also in the discord, he was lurking in the chat earlier🙃

#

Is there anything interesting in the errors? Get-Error

#

Whats the profiler error

#

Nice

valid pecan
#

uhm, i just noticed the argumentcompleter, thats not really how you implement IValidateSetValuesGenerator..
can loose the whole argumentcompleter + ValidateScript thingy and just replace it with:

    [ValidateSet([Categoriex], ErrorMessage = "Value '{0}' is invalid. Try one of: {1}")]

you probably need to move the class so its defined before the function and not inside the function

https://gist.github.com/trackd/104a89d69600c7c278920ac986d5d089 like this