Here’s what I’ve found out so far. In trying to figure out why this debuggingMode was being set, I discovered the cmdlet Set-PSDebug -Off. When I do this on my local machine, I can see the _debuggingMode being changed to 0, but when I did this on one of these affected machines, it would remain a “1”. Looking at the reflected code, it would only do this if there were breakpoints currently set in the session. If I ran Get-PSBreakPoint, it would return nothing. But then I ran a “Get-Command Get-PSBreakpoint | select *” on affected machines, this was CommandType of Function and on non-affected machines it was CmdLet. The definition on affected machines looked like this:
[CmdletBinding(DefaultParametersetName="Script")]
param(
[parameter(Mandatory = $True,ValueFromPipeline = $True,ValueFromPipelineByPropertyName =
$True,ValueFromRemainingArguments = $True,ParameterSetName = "Variable")]
[string[]]
$Script,
[parameter(Mandatory = $True,Position = 0,ValueFromPipeline = $True,ParameterSetName = "Id")]
[int[]]
$Id,
[parameter(Mandatory = $True,ParameterSetName = "Variable")]
[string[]]
$Variable,
[parameter(Mandatory = $True,ParameterSetName = "Command")]
[string[]]
$Command,
[parameter(Mandatory = $True,Position = 0,ValueFromPipeline = $True,ParameterSetName = "Type")]
[Microsoft.PowerShell.Commands.BreakpointType[]]
$Type)
$local:origGetPsbreakpoint = Get-Command Get-PSBreakpoint -Type cmdlet
if ((Test-Path variable:psBoundParameters) -or $psBoundParameters.count) {
return ((& $origGetPsbreakpoint @psBoundParameters) | where {!($_.Action -and
$_.Action.ToString().toLower().contains('<#sentinelbreakpoints#>'))})
} else {
return ((& $origGetPsbreakpoint @args) | where {!($_.Action -and
$_.Action.ToString().toLower().contains('<#sentinelbreakpoints#>'))})
}
In this code I can see “<#sentinelbreakpoints#>” and SentinelOne is our antivirus product. Once I new this, I could call the original cmdlet version of Get-PSBreakpoint and there were 58 Variable and Command breakpoints with Actions on them. It looks like something in SentinelOne is injecting breakpoints into the powershell code so that it can inject itself into certain calls or changes of variables. Because these breakpoints are there, it causes the powershell code to see the debugger active and everytime a variable is set, it is calling ScriptDebugger.CheckVariableWrite which checks the SystemLockdownPolicy which is where I’m seeing the check for the existence of the wldp.dll.
Also, when I decompiled the System.Management.Automation assembly on my machine, I saw this:
But when I grabbed the assembly from one of the affected machines, this is what this method looked like:
I then checked and found that I did indeed have different versions of powershell 5.1 running on my machine vs the server machines.
My next step is going to see if I can get PS 5 updated on the machine and if that doesn’t improve things, I’m going to talk to our AV guys and see what powershell switches they have to potentially turn this off.