Created
April 16, 2019 20:01
-
-
Save realslacker/d1b5463c2db6689bd7e458d3babdc048 to your computer and use it in GitHub Desktop.
A module with expanded functionality base on original work by Steve Lee and Graeme Bray. See Set-WMINameSpaceSecurity.ps1 for original.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
Disclaimer: | |
This module is provided AS IS without warranty of any kind. This work is based off work by | |
other talented individuals, and should not be considered an original work. | |
Modified into module by Shannon Graybrook | |
Modified by Graeme Bray | |
Original Content by Steve Lee | |
#> | |
$WBEM_ENABLE = 0x00001 | |
$WBEM_METHOD_EXECUTE = 0x00002 | |
$WBEM_FULL_WRITE_REP = 0x00004 | |
$WBEM_PARTIAL_WRITE_REP = 0x00008 | |
$WBEM_WRITE_PROVIDER = 0x00010 | |
$WBEM_REMOTE_ACCESS = 0x00020 | |
$WBEM_RIGHT_SUBSCRIBE = 0x00040 | |
$WBEM_RIGHT_PUBLISH = 0x00080 | |
$READ_CONTROL = 0x20000 | |
$WRITE_DAC = 0x40000 | |
$OBJECT_INHERIT_ACE_FLAG = 0x00001 | |
$CONTAINER_INHERIT_ACE_FLAG = 0x00002 | |
$ACCESS_ALLOWED_ACE_TYPE = 0x00000 | |
$ACCESS_DENIED_ACE_TYPE = 0x00001 | |
<# | |
.SYNOPSIS | |
Converts a permission set to an access mask | |
.PARAMETER Permission | |
The permissions to include in the access mask | |
#> | |
function Get-AccessMaskFromPermission { | |
param( | |
[ValidateSet('Enable','MethodExecute','FullWrite','PartialWrite','ProviderWrite','RemoteAccess','ReadSecurity','WriteSecurity')] | |
[string[]] | |
$Permission | |
) | |
$PermissionsTable = @{ | |
Enable = $WBEM_ENABLE | |
MethodExecute = $WBEM_METHOD_EXECUTE | |
FullWrite = $WBEM_FULL_WRITE_REP | |
PartialWrite = $WBEM_PARTIAL_WRITE_REP | |
ProviderWrite = $WBEM_WRITE_PROVIDER | |
RemoteAccess = $WBEM_REMOTE_ACCESS | |
ReadSecurity = $READ_CONTROL | |
WriteSecurity = $WRITE_DAC | |
} | |
$AccessMask = 0 | |
foreach ($PermissionItem in $Permission) { | |
if ( $PermissionsTable.Keys -notcontains $PermissionItem ) { | |
throw ( "Unknown permission: {0}`nValid permissions: {1}" -f $PermissionItem, ( $PermissionsTable.Keys -join ', ' ) ) | |
} | |
$AccessMask += $PermissionsTable.$PermissionItem | |
} | |
$AccessMask | |
} | |
<# | |
.SYNOPSIS | |
Converts an access mask back into a permission set | |
.PARAMETER AccessMask | |
The access mask to convert to permissions | |
#> | |
function Get-PermissionFromAccessMask { | |
param( | |
[int] | |
$AccessMask | |
) | |
$PermissionsTable = @{ | |
Enable = $WBEM_ENABLE | |
MethodExecute = $WBEM_METHOD_EXECUTE | |
FullWrite = $WBEM_FULL_WRITE_REP | |
PartialWrite = $WBEM_PARTIAL_WRITE_REP | |
ProviderWrite = $WBEM_WRITE_PROVIDER | |
RemoteAccess = $WBEM_REMOTE_ACCESS | |
ReadSecurity = $READ_CONTROL | |
WriteSecurity = $WRITE_DAC | |
} | |
foreach ( $Key in $PermissionsTable.Keys ) { | |
if ( $AccessMask -band $PermissionsTable[$Key] ) { $Key } | |
} | |
} | |
<# | |
.SYNOPSIS | |
Add security access on WMI name space. | |
.PARAMETER Namespace | |
The WMI namespace | |
.PARAMETER Account | |
The account to add. Should be DOMAIN\user format, but also accepts other standard formats. | |
.PARAMETER Permissions | |
The permissions to set. | |
.EXAMPLE | |
Add-WmiNamespaceAccessRule -Namespace root/CIMv2 -Account "CONTOSO\ServiceAccount" -Permissions Enable, RemoteAccess -ComputerName REMOTE_DC01 -Credential (Get-Credential) | |
.EXAMPLE | |
Add-WmiNamespaceAccessRule root/CIMv2 ServiceAccount Enable,RemoteAccess | |
#> | |
function Add-WmiNameSpaceAccessRule { | |
param( | |
[Parameter(Mandatory=$true,Position=0)] | |
[string] | |
$Namespace, | |
[Parameter(Mandatory=$true,Position=1)] | |
[string] | |
$Account, | |
[Parameter(Mandatory=$true, Position=2)] | |
[ValidateSet('Enable','MethodExecute','FullWrite','PartialWrite','ProviderWrite','RemoteAccess','ReadSecurity','WriteSecurity')] | |
[string[]] | |
$Permissions, | |
[switch] | |
$AllowInherit, | |
[switch] | |
$Deny, | |
[string] | |
$ComputerName, | |
[pscredential] | |
$Credential | |
) | |
process { | |
$ErrorActionPreference = "Stop" | |
$CredentialSplat = @{} | |
if ( $Credential ) { $CredentialSplat.Credential = $Credential } | |
$ComputerNameSplat = @{} | |
if ( $ComputerName ) { $ComputerNameSplat.ComputerName = $ComputerName } | |
$InvokeParams = @{ | |
Namespace = $Namespace | |
Path = "__systemsecurity=@" | |
} | |
$Output = Invoke-WmiMethod @InvokeParams @ComputerNameSplat @CredentialSplat -Name GetSecurityDescriptor | |
if ( $Output.ReturnValue -ne 0 ) { | |
throw ( 'GetSecurityDescriptor failed: {0}' -f $Output.ReturnValue ) | |
} | |
$Acl = $Output.Descriptor | |
$ComputerName = (Get-WmiObject @ComputerNameSplat @CredentialSplat Win32_ComputerSystem).Name | |
if ( $Account.Contains('@') ) { | |
$AccountName, $Domain = $Account.Split('@') | |
} elseif ( $Account.Contains('\') ) { | |
$Domain, $AccountName = $Account.Split('\') | |
} else { | |
$Domain = $ComputerName | |
$AccountName = $Account | |
} | |
if ( $Domain -eq '.' -or $Domain -eq 'BUILTIN' ) { | |
$Domain = $ComputerName | |
} | |
if ( $Domain.Contains('.') ) { | |
Write-Warning 'Domain provided appears to be a DNS domain, attempting to resolve NETBIOS domain name. This can cause a delay in processing, in the future provide the NETBIOS domain for faster processing.' | |
$Domain = Get-WmiObject -Class win32_ntdomain | | |
Where-Object { $_.DomainName -eq $Domain -or $_.DnsForestName -eq $Domain } | | |
Select-Object -ExpandProperty DomainName | |
} | |
$GetAccountParams = @{ | |
Class = 'Win32_Account' | |
Filter = 'Domain="{0}" and Name="{1}"' -f $Domain, $AccountName | |
} | |
if ( -not( $Win32Account = Get-WmiObject @GetAccountParams ) ) { | |
throw ( 'Account was not found: {0}' -f $Account ) | |
} | |
$AccessMask = Get-AccessMaskFromPermission -Permission $Permissions | |
$Ace = (New-Object System.Management.ManagementClass('Win32_Ace')).CreateInstance() | |
$Ace.AccessMask = $AccessMask | |
$Ace.AceFlags = ( 0, ( $OBJECT_INHERIT_ACE_FLAG + $CONTAINER_INHERIT_ACE_FLAG ) )[ $AllowInherit.IsPresent ] | |
$Trustee = (New-Object System.Management.ManagementClass('Win32_Trustee')).CreateInstance() | |
$Trustee.SidString = $Win32Account.Sid | |
$Ace.Trustee = $Trustee | |
$Ace.AceType = ( $ACCESS_ALLOWED_ACE_TYPE, $ACCESS_DENIED_ACE_TYPE )[ $Deny.IsPresent ] | |
$Acl.DACL += $Ace.psobject.immediateBaseObject | |
$SetParams = @{ | |
Name = 'SetSecurityDescriptor' | |
ArgumentList = $Acl.psobject.immediateBaseObject | |
} | |
$Output = Invoke-WmiMethod @SetParams @InvokeParams @ComputerNameSplat @CredentialSplat | |
if ( $Output.ReturnValue -ne 0 ) { | |
throw ( 'SetSecurityDescriptor failed: {0}' -f $Output.ReturnValue ) | |
} | |
} | |
} | |
<# | |
.SYNOPSIS | |
Remove security access on WMI name space. | |
.PARAMETER Namespace | |
The WMI namespace | |
.PARAMETER Account | |
The account to add. Should be DOMAIN\user format, but also accepts other standard formats. | |
.EXAMPLE | |
Remove-WmiNamespaceAccessRule -Namespace root/CIMv2 -Account "CONTOSO\ServiceAccount" -ComputerName REMOTE_DC01 -Credential (Get-Credential) | |
.EXAMPLE | |
Remove-WmiNamespaceAccessRule root/CIMv2 ServiceAccount | |
#> | |
function Remove-WmiNameSpaceAccessRule { | |
param( | |
[Parameter(Mandatory=$true,Position=0)] | |
[string] | |
$Namespace, | |
[Parameter(Mandatory=$true,Position=1)] | |
[string] | |
$Account, | |
[string] | |
$ComputerName, | |
[pscredential] | |
$Credential | |
) | |
process { | |
$ErrorActionPreference = "Stop" | |
$CredentialSplat = @{} | |
if ( $Credential ) { $CredentialSplat.Credential = $Credential } | |
$ComputerNameSplat = @{} | |
if ( $ComputerName ) { $ComputerNameSplat.ComputerName = $ComputerName } | |
$InvokeParams = @{ | |
Namespace = $Namespace | |
Path = "__systemsecurity=@" | |
} | |
$Output = Invoke-WmiMethod @InvokeParams @ComputerNameSplat @CredentialSplat -Name GetSecurityDescriptor | |
if ( $Output.ReturnValue -ne 0 ) { | |
throw ( 'GetSecurityDescriptor failed: {0}' -f $Output.ReturnValue ) | |
} | |
$Acl = $Output.Descriptor | |
$ComputerName = (Get-WmiObject @ComputerNameSplat @CredentialSplat Win32_ComputerSystem).Name | |
if ( $Account.Contains('@') ) { | |
$AccountName, $Domain = $Account.Split('@') | |
} elseif ( $Account.Contains('\') ) { | |
$Domain, $AccountName = $Account.Split('\') | |
} else { | |
$Domain = $ComputerName | |
$AccountName = $Account | |
} | |
if ( $Domain -eq '.' -or $Domain -eq 'BUILTIN' ) { | |
$Domain = $ComputerName | |
} | |
if ( $Domain.Contains('.') ) { | |
Write-Warning 'Domain provided appears to be a DNS domain, attempting to resolve NETBIOS domain name. This can cause a delay in processing, in the future provide the NETBIOS domain for faster processing.' | |
$Domain = Get-WmiObject -Class win32_ntdomain | | |
Where-Object { $_.DomainName -eq $Domain -or $_.DnsForestName -eq $Domain } | | |
Select-Object -ExpandProperty DomainName | |
} | |
$GetAccountParams = @{ | |
Class = 'Win32_Account' | |
Filter = 'Domain="{0}" and Name="{1}"' -f $Domain, $AccountName | |
} | |
if ( -not( $Win32Account = Get-WmiObject @GetAccountParams ) ) { | |
throw ( 'Account was not found: {0}' -f $Account ) | |
} | |
[System.Management.ManagementBaseObject[]]$NewDACL = @() | |
foreach ( $Ace in $Acl.DACL ) { | |
if ( $Ace.Trustee.SidString -ne $Win32Account.Sid ) { | |
$NewDACL += $Ace.psobject.immediateBaseObject | |
} | |
} | |
$Acl.DACL = $NewDACL.psobject.immediateBaseObject | |
$SetParams = @{ | |
Name = 'SetSecurityDescriptor' | |
ArgumentList = $Acl.psobject.immediateBaseObject | |
} | |
$Output = Invoke-WmiMethod @SetParams @InvokeParams @ComputerNameSplat @CredentialSplat | |
if ( $Output.ReturnValue -ne 0 ) { | |
throw ( 'SetSecurityDescriptor failed: {0}' -f $Output.ReturnValue ) | |
} | |
} | |
} | |
<# | |
.SYNOPSIS | |
Get security access on WMI name space. | |
.PARAMETER Namespace | |
The WMI namespace | |
.PARAMETER Account | |
The account to retrieve access for. Should be DOMAIN\user format, but also accepts other standard formats. | |
.EXAMPLE | |
Get-WmiNamespaceAccessRule -Namespace root/CIMv2 -Account "CONTOSO\ServiceAccount" -ComputerName REMOTE_DC01 -Credential (Get-Credential) | |
.EXAMPLE | |
Get-WmiNamespaceAccessRule root/CIMv2 ServiceAccount | |
#> | |
function Get-WmiNameSpaceAccessRule { | |
param( | |
[Parameter(Mandatory=$true,Position=0)] | |
[string] | |
$Namespace, | |
[Parameter(Mandatory=$true,Position=1)] | |
[string] | |
$Account, | |
[string] | |
$ComputerName, | |
[pscredential] | |
$Credential | |
) | |
process { | |
$ErrorActionPreference = "Stop" | |
$CredentialSplat = @{} | |
if ( $Credential ) { $CredentialSplat.Credential = $Credential } | |
$ComputerNameSplat = @{} | |
if ( $ComputerName ) { $ComputerNameSplat.ComputerName = $ComputerName } | |
$InvokeParams = @{ | |
Namespace = $Namespace | |
Path = "__systemsecurity=@" | |
} | |
$Output = Invoke-WmiMethod @InvokeParams @ComputerNameSplat @CredentialSplat -Name GetSecurityDescriptor | |
if ( $Output.ReturnValue -ne 0 ) { | |
throw ( 'GetSecurityDescriptor failed: {0}' -f $Output.ReturnValue ) | |
} | |
$Acl = $Output.Descriptor | |
$ComputerName = (Get-WmiObject @ComputerNameSplat @CredentialSplat Win32_ComputerSystem).Name | |
if ( $Account.Contains('@') ) { | |
$AccountName, $Domain = $Account.Split('@') | |
} elseif ( $Account.Contains('\') ) { | |
$Domain, $AccountName = $Account.Split('\') | |
} else { | |
$Domain = $ComputerName | |
$AccountName = $Account | |
} | |
if ( $Domain -eq '.' -or $Domain -eq 'BUILTIN' ) { | |
$Domain = $ComputerName | |
} | |
if ( $Domain.Contains('.') ) { | |
Write-Warning 'Domain provided appears to be a DNS domain, attempting to resolve NETBIOS domain name. This can cause a delay in processing, in the future provide the NETBIOS domain for faster processing.' | |
$Domain = Get-WmiObject -Class win32_ntdomain | | |
Where-Object { $_.DomainName -eq $Domain -or $_.DnsForestName -eq $Domain } | | |
Select-Object -ExpandProperty DomainName | |
} | |
$GetAccountParams = @{ | |
Class = 'Win32_Account' | |
Filter = 'Domain="{0}" and Name="{1}"' -f $Domain, $AccountName | |
} | |
if ( -not( $Win32Account = Get-WmiObject @GetAccountParams ) ) { | |
throw ( 'Account was not found: {0}' -f $Account ) | |
} | |
$Ace = $Acl.DACL | | |
Where-Object { $_.Trustee.SidString -eq $Win32Account.Sid } | | |
ForEach-Object { $_.psobject.immediateBaseObject } | |
$ReturnObj = 0 | Select-Object Account, SID, Permissions, AllowInherit, Deny | |
$ReturnObj.Account = '{0}\{1}' -f $Ace.Trustee.Domain, $Ace.Trustee.Name | |
$ReturnObj.SID = $Ace.Trustee.SIDString | |
$ReturnObj.Permissions = Get-PermissionFromAccessMask -AccessMask $Ace.AccessMask | |
$ReturnObj.AllowInherit = $Ace.AceFlags -eq ( $OBJECT_INHERIT_ACE_FLAG + $CONTAINER_INHERIT_ACE_FLAG ) | |
$ReturnObj.Deny = [bool]$Ace.AceType | |
$ReturnObj | |
} | |
} | |
Export-ModuleMember -Function 'Add-WmiNameSpaceAccessRule', 'Remove-WmiNameSpaceAccessRule', 'Get-WmiNameSpaceAccessRule' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment