Powershell script Set-MpPreference not working correctly

1.7k views Asked by At

I've written a shell script that will exclude a folder during Microsoft Defender Antivirus scanning. I don't have a lot of experience with shell scripting, and this is what I come up with:

Set-MpPreference -ExclusionPath D:\vpostest
echo "Exclusion Success"
Read-Host -Prompt "Press Enter to exit"

The first line of the code is where I mention the exclusion, and the following is just some kind of prompt to notify the user that the exclusion is a success (it is still a work in progress).

Once I run the script, I receive an error:

Set-MpPreference : Operation failed with the following error: 0x%1!x!
At C:\Users\zainur.ariffin\Desktop\Powershell test\autoExclusion.ps1:1 char:1
+ Set-MpPreference -ExclusionPath D:\vpostest
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (MSFT_MpPreference:root\Microsoft\...FT_MpPreference) [Set-MpPreference], CimException
    + FullyQualifiedErrorId : HRESULT 0xc0000142,Set-MpPreference

If I'm not mistaken, I've read that the following error indicates that Microsoft Defender Antivirus was not enabled. I have already enabled this feature and restarted my computer, and even check with 'Get-MpComputerStatus'. However, the same error keeps appearing. Why is this happening?

2

There are 2 answers

0
mklement0 On

You found the solution:

  • The Set-MpPreference cmdlet from the ConfigDefender module must be run with elevation (as administrator), as all cmdlets from this module that modify settings must.

  • It is unfortunate that the error message reported by these cmdlets is so obscure (as of v1.0 of the module); if the need to elevate were stated clearly, the solution would be obvious.


Ways to ensure that your script runs with elevation:
  • Ad hoc, assuming your script-file path is stored in $scriptFile:

    Start-Process -Verb RunAs powershell "-NoExit -File `"$scriptFile`""
    
    • -NoExit keeps the elevated session open after your script exits, so you can examine its output.
    • Using the -File CLI parameter is preferable for invoking script files, and the embedded double-quoting (`"...`") ensures that paths with spaces are handled correctly.
    • Note that the elevated session's working directory (location) will be C:\Windows\System32 (if you used pwsh, the PowerShell (Core) CLI instead, the caller's working directory would be preserved); if that is a problem, either modify your script to change the location or use a -Command (-c) CLI call that changes the location before invoking your script - see this answer.
  • Using self-elevation, i.e. modifying your script so that it re-invokes itself with elevation on demand, by placing the following at the start of your script:

    if (-not (net session 2>$null)) { # Test if the session is elevated.
      Write-Warning "Re-invoking with elevation, of necessity in a new window..."
      exit (
        Start-Process -Wait -PassThru -Verb RunAs (Get-Process -Id $PID).Path "-NoExit -File `"$PSCommandPath`""
      ).ExitCode
    }
    
    # ... rest of your script, which now runs with elevation
    # If powershell.exe was called, the working dir will be C:\Windows\System32.
    # pwsh.exe preserves the caller's working dir.
    
    • Note: This assumes that your script doesn't need to support parameters; if it does, a robust solution requires a lot more effort: see this answer.

    • The automatic $PSCommandPath variable contains the full path of the running script.

    • (Get-Process -Id $PID).Path is used in lieu of hard-coding powershell to ensure that you're using the same PowerShell executable that was used to launch the script; that is, if you launched from Windows PowerShell, it'll use powershell.exe, if you launched from PowerShell (Core) 7+, it'll use pwsh.exe.

  • Creating a shortcut file (*.lnk) interactively:

    • Since *.ps1 files are not directly executable from outside PowerShell, using the path of such a file alone as the shortcut target won't work: it'll be treated as a document to open for editing instead.

      • This is also the reason that the Run as administrator checkbox is disabled in the Advanced... (Advanced Properties) sub-dialog.
    • Therefore, you must call the script explicitly via PowerShell's CLI; specify the following target in combination with checking Run as administrator:

       powershell.exe -NoExit -File "C:\path\to\your\script.ps1" 
      
    • Note that programmatic creation of a shortcut file, via the WScript.Shell COM object is unfortunately not an option, because it doesn't expose a property to request running as administrator.

0
Zafzaa On

This is for anyone who have the same problem as me

So I found out that the reason why the script file doesn't run properly is because I didn't run powershell as administrator. But how to run the shell script file as administrator?

I have tried to create a shortcut from the script file, and try to enable 'run as administrator' from the properties, but the option is greyed out. Meaning I couldn't choose that option so I have to find another way.

So I come to a conclusion that I need to create a script file that will grant admin privileges to the script that I want. This is because it's not possible to grant administrative privileges to a script within the script itself. The following is the command I use to grant admin privileges:

Start-Process powershell -Verb runAs -ArgumentList $scriptFile

The "$scriptFile" need to be the script file that you intended to use. I hope this is useful for people who have the same problem as me.