Anti-Virus
Information about anti-virus and packaged applications.
PowerShell that is packaged as an executable can often trigger anti-virus software after packaged. The use of PowerShell within malicious executables has led to false positives being found in your own packages. This document contains information about anti-virus and PowerShell Pro Tools packaging.
These tests were completed with PowerShell Pro Tools 2021.9.2.

Default Package Detection

The packaging itself will not flag anti-virus for most providers. You will see that if you package an empty PS1 file and upload it to VirusTotal, most AV providers will not flag the executable.
VirusTotal
VirusTotal
The package settings for this are the default ones provided by the Visual Studio Code extension.
1
@{
2
Root = 'c:\Users\adamr\Desktop\Tests\test.ps1'
3
OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
4
Package = @{
5
Enabled = $true
6
Obfuscate = $false
7
HideConsoleWindow = $false
8
DotNetVersion = 'v4.6.2'
9
FileVersion = '1.0.0'
10
FileDescription = ''
11
ProductName = ''
12
ProductVersion = ''
13
Copyright = ''
14
RequireElevation = $false
15
ApplicationIconPath = ''
16
PackageType = 'Console'
17
}
18
Bundle = @{
19
Enabled = $true
20
Modules = $true
21
# IgnoredModules = @()
22
}
23
}
Copied!

Custom Script Results

As you can see when we start to include additional PowerShell script, you will begin to see certain AV providers begin to flag the results. This example uses the Clean Windows 10 PowerShell script.
Additionally, we enabled require elevation in the package.psd1 file to ensure that administrator access is allowed to modify the Windows features.
1
@{
2
Root = 'c:\Users\adamr\Desktop\Tests\test.ps1'
3
OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
4
Package = @{
5
Enabled = $true
6
Obfuscate = $false
7
HideConsoleWindow = $false
8
DotNetVersion = 'v4.6.2'
9
FileVersion = '1.0.0'
10
FileDescription = ''
11
ProductName = ''
12
ProductVersion = ''
13
Copyright = ''
14
RequireElevation = $true
15
ApplicationIconPath = ''
16
PackageType = 'Console'
17
}
18
Bundle = @{
19
Enabled = $true
20
Modules = $true
21
# IgnoredModules = @()
22
}
23
}
Copied!
This example yields another false positive.
VirusTotal
VirusTotal

Obfuscation

Obfuscation does not work with PowerShell 7
Obfuscation of the assembly greatly increases the probability of the executable being marked as malicious. We are using the same Windows 10 clean up script but have now enabled obfuscation.
The package.psd1 has been updated to turn on obfuscation.
1
@{
2
Root = 'c:\Users\adamr\Desktop\Tests\test.ps1'
3
OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
4
Package = @{
5
Enabled = $true
6
Obfuscate = $true
7
HideConsoleWindow = $true
8
DotNetVersion = 'v4.6.2'
9
FileVersion = '1.0.0'
10
FileDescription = ''
11
ProductName = ''
12
ProductVersion = ''
13
Copyright = ''
14
RequireElevation = $true
15
ApplicationIconPath = ''
16
PackageType = 'Console'
17
}
18
Bundle = @{
19
Enabled = $true
20
Modules = $true
21
# IgnoredModules = @()
22
}
23
}
24
Copied!
As you can see, the number of AV vendors to flag the assembly has increased to 10.
VirusTotal
VirusTotal

Code Signing

While not directly supported within PowerShell Pro Tools, code signing can reduce the number of false positives. Using the same script and package settings as in the obfuscated example, we can use signtool to sign the resulting executable.
1
signtool sign /f some.pfx /sha1 MYSHA1 /p MYPASSWORD .\text.exe
Copied!
This results in an executable that is only flagged by 2 vendors.
VirusTotal
VirusTotal

Modules

Including modules also increases the probability of false positives. In this example, we are packaging the ActiveDirectory module and obfuscating the resulting binary. 12 vendors flag this executable.
VirusTotal
VirusTotal
Again, signing the binary greatly reduces the number of false positives. Only 3 vendors now flag that same binary.
VirusTotal
VirusTotal

PowerShell 7

PowerShell 7 executables are packaged differently. Rather than relying on the local PowerShell DLLs, the PowerShell SDK is packaged with the binary. This results in a larger binary but it's completely self-contained.
I've changed the package settings to this. We are using the .NET Core 3.1 SDK and the 7.0.3 PowerShell SDK. This is again packaging the clean up script and the Active Directory module.
1
@{
2
Root = 'c:\Users\adamr\Desktop\Tests\test.ps1'
3
OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
4
Package = @{
5
Enabled = $true
6
Obfuscate = $false
7
HideConsoleWindow = $true
8
DotNetVersion = 'netcoreapp3.1'
9
PowerShellVersion = '7.0.3'
10
FileVersion = '1.0.0'
11
FileDescription = ''
12
ProductName = ''
13
ProductVersion = ''
14
Copyright = ''
15
RequireElevation = $false
16
ApplicationIconPath = ''
17
PackageType = 'Console'
18
}
19
Bundle = @{
20
Enabled = $true
21
Modules = $true
22
# IgnoredModules = @()
23
}
24
}
25
Copied!
In this example, the package is flagged by 1 AV vendor.
VirusTotal
VirusTotal

Cmdlet Usage

Certain cmdlets will also cause AV engines to flag. For example, if you use the Set-MpPreference cmdlet within your script, it may flag several vendors. This cmdlet is used for disabling Windows Defender.
1
Set-MpPreference -DisableRealtimeMonitoring $true
Copied!
This script was flagged by 8 vendors.
VirusTotal
VirusTotal
Obfuscating and code signing this same assembly, reduces that number to 2.
VirusTotal
VirusTotal
Last modified 19d ago