Tuesday, February 21, 2012

Get System DEP Setting with PowerShell

The data execution policy can be obtained using bcdedit /enum however that command has a lot of output. I needed to get the system DEP policy setting in PowerShell so I found a Win32 function called GetSystemDEPPolicy. So in order to call this from PowerShell we'll need to use p/invoke again. Here's how:

function Get-SystemDEPPolicy {
Add-Type -Namespace Win32 -Name DEP -MemberDefinition @"
[DllImport("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern int GetSystemDEPPolicy();

public static int GetCurrentSystemDEPPolicy() {
return GetSystemDEPPolicy();
}
"@
$policyCode = [Win32.DEP]::GetCurrentSystemDEPPolicy()
switch ($policyCode) {
0 {Write-Output 'AlwaysOff'}
1 {Write-Output 'AlwaysOn'}
2 {Write-Output 'OptIn'}
3 {Write-Output 'OptOut'}
}
}

Update: I should of looked at WMI first! There is a property named DataExecutionPrevention_SupportPolicy in the Win32_OperatingSystem class that also stores this information and it's easier to retrieve...


Get-WmiObject -Class Win32_OperatingSystem -Property DataExecutionPrevention_SupportPolicy

Monday, February 20, 2012

Unblocking Files with PowerShell

When you download a file from the internet you may of seen this:

2012-02-19 01h38_17

If the file is an executable and you try to run it, you will be prompted if you want to run the file… Yea, yea… I just freaking downloaded it, I want to run it already! If you download a ZIP file (such as the Sysinternals Suite) you'll have to unblock every program in it…

So what's really going on is that something called an alternate data stream get's created for the file when you save it to disk. This is a special feature of NTFS that allows a file name to reference more than one data stream on disk. The primary data stream is just the data that the filename is referencing. So Test.zip points to a data stream and that's where the ZIP file data is stored. Alternate data streams are stored and accessed with the name of the file plus ':Data_Stream_Name' (a colon and the name of the alternate stream). These additional streams are hidden from Windows Explorer and the command prompt directory listing. Only special methods allow you to access them. When a file is downloaded from the internet an alternate access stream is created with the name 'Zone.Identifier'. The contents look like this:

ZoneId 3 means it came from the internet. This is what Windows uses to determine whether or not it should block the file. You can edit the file by opening it with Notepad from a command prompt like this:

However you cannot delete the alternate access stream from disk using this approach, only delete or change it's contents. There is a function called DeleteFile in Win32 API that will allow you to delete an alternate access stream however we can't call this from PowerShell directly. We will need to p/invoke using the Add-Type cmdlet.

I've wrapped this into a portable function that allows pipeline input. So you can pipe an entire set of files to this like so:

As I write this, PowerShell 3 is current in CTP2 and it does include a cmdlet for this. However if you are using PowerShell v2 this is the way to go.

Sunday, February 12, 2012

Fixing Unresolvable NTFS ACL Accounts

An interesting question came up on SuperUser the other day. The OP wanted to know how to change the account of a NTFS ACL but still retain all of the ACL settings (privileges, inheritance etc.…). This could be needed if the original account was deleted, or if the ACL was on a drive that was moved to another machine etc.…

When the ACL entry has an unresolvable account it will appear like this:

image

The first thing that came to mind was to edit the SDDL string. The SDDL is a not so easy to read string representation of the ACL. It looks like this:

Easy to read huh?

You can learn all about the format on MSDN, however the format is not important for our purpose here. All we need to do is replace the SID with the SID of the account we want.

So first lets use the Win32_Account WMI class to get a list of user account SIDs:

This will get all account types from the local machine and the domain if the machine is on a domain which could make this command take a really long time.

To make it go faster we’ll filter the query a little bit. There are a couple properties of this class we can use to reduce the run time.

  • Name
  • SidType

    (1) User
    (2) Group
    (3) Domain
    (4) Alias
    (5) WellKnownGroup
    (6) DeletedAccount
    (7) Invalid
    (8) Unknown
    (9) Computer

  • LocalAccount

So to get the SID of a local user account named NewAccount we’ll use:

To find the SID of the broken ACL entry we’ll use the Get-ACL cmdlet. The ACE’s are stored in the Access property returned by the Get-Acl object. To retrieve the SID of the entry which account is unknown we’ll use the Translate method to find that one that can’t translate to an NTAccount object. We also aren’t interested in ACE’s that are inherited so we’ll filter them out.

The invalid SIDs are stored in the array $invalidSids.

Now we can do a simple string search and replace in the SDDL string.

The last step is to set the ACL with the updated SDDL. To do this we’ll use the SetSecurityDescriptorSddlForm method.

And that’s it. The ACL is now updated with the account but all of the previous ACE settings are retained as we wanted.

image