Resources/SecurityPolicy.helper.psm1
function Invoke-SecEdit { <# .SYNOPSIS Private function that wraps secedit.exe .DESCRIPTION If system is domain joined, adds '/mergedpolicy' to secedit arguements to get LSDOU results. .EXAMPLE Invoke-SecEdit .NOTES Modified auditpol.exe wrapper .LINK https://github.com/dsccommunity/AuditPolicyDsc/blob/dev/DSCResources/AuditPolicyResourceHelper/AuditPolicyResourceHelper.psm1 #> [OutputType([System.String])] [CmdletBinding()] param() $secEditResultFile = '' $currentSecurityPolicyFilePath = Join-Path -Path $env:temp -ChildPath "SecurityPolicy_$((Get-Date).ToString('yyyyMMddHmmss')).inf" # set the base commands to execute [string[]] $seceditArguments = @('/export',"/cfg $currentSecurityPolicyFilePath") if((Get-CimInstance -ClassName Win32_ComputerSystem).PartOfDomain) { # include domain policy with /mergedpolicy $seceditArguments += '/mergedpolicy' } try { # Use System.Diagnostics.Process to process the secedit command $process = New-Object System.Diagnostics.Process $process.StartInfo.Arguments = $seceditArguments $process.StartInfo.CreateNoWindow = $true $process.StartInfo.FileName = 'secedit.exe' $process.StartInfo.RedirectStandardOutput = $true $process.StartInfo.UseShellExecute = $false $null = $process.Start() $processReturn = $process.StandardOutput.ReadToEnd() if($processReturn.Trim().StartsWith('You do not have sufficient permissions to perform this command.')) { throw } $secEditResultFile = $currentSecurityPolicyFilePath Write-Verbose -Message " File written: $($currentSecurityPolicyFilePath)" $process.Dispose() } catch [System.ComponentModel.Win32Exception] { # Catch error if the secedit command is not found on the system Write-Error -Message 'secedit.exe not found.' } catch { # Catch the error thrown if the lastexitcode is not 0 [string] $errorString = $error[0].Exception + ` " `nLASTEXITCODE = $LASTEXITCODE" + ` " `nCommand = secedit.exe $seceditArguments" + ` " `nUser = $($env:USERDOMAIN)\$($env:USERNAME)" + ` " `nMake sure that you are running as the local administrator or have opened the command prompt using the `'Run as administrator`' option.`n" Write-Error -Message $errorString } return $secEditResultFile } # end function Invoke-SecEdit function ConvertTo-ReverseHashTable { <# .SYNOPSIS Reverses HashTable by swapping the keys and values. #> [OutputType([System.Collections.Hashtable])] [CmdletBinding()] param( [parameter(Mandatory=$true)] [System.Collections.Hashtable] # HashTable to reverse. $HashTable ) $reverseHashTable = @{} foreach($key in $HashTable.Keys) { $reverseHashTable.Add($HashTable[$key],$key) } return $reverseHashTable } # end function ConvertTo-ReverseHashTable Function Convert-SecurityPolicyIniToHash { <# .SYNOPSIS Parses configuration file into a hashtable. .INPUTS System.String .OUTPUTS System.Collections.Hashtable .LINK https://blogs.technet.microsoft.com/heyscriptingguy/2011/08/20/use-powershell-to-work-with-any-ini-file/ #> [OutputType([System.Collections.Hashtable])] [CmdletBinding()] param ( [parameter(Mandatory=$true)] [ValidateScript({Test-Path $_})] [string] # Path to configuration file. $Path ) $config = @{} switch -regex -file $Path { "^.*\[(.+)\].*$" # Section { $section = $matches[1] if($section.ToString().Trim().StartsWith('#') -eq $false) { $config.Add($section.Trim(),@{}) } } "(.+?)\s*=(.*)" # Key { $name,$value = $matches[1..2] if($name.ToString().Trim().StartsWith('#') -eq $false) { $config[$section].Add($name.Trim(), $value.Trim()) } } } # remove file once converted to hashtable if(Test-Path $Path) { Remove-Item $Path if($(Test-Path $Path) -eq $false) { Write-Verbose -Message " Removed File: $($Path)" } } return $config } # End Function Convert-SecurityPolicyIniToHash function Get-SecurityPolicyData { <# .SYNOPSIS Gets security policy data helper files extracted from SecurityPolicyDsc source. .LINK https://github.com/dsccommunity/SecurityPolicyDsc/tree/master/source #> [OutputType([System.Collections.Hashtable])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateSet("AccountPolicy", "SecurityOption", "UserRights")] [System.String] $Section ) $returnData = @{} $filePath = '' switch($Section.ToUpper()) { "ACCOUNTPOLICY" { $filePath = Join-Path $($PSScriptRoot) -ChildPath 'AccountPolicyData.psd1' } "SECURITYOPTION" { $filePath = Join-Path $($PSScriptRoot) -ChildPath 'SecurityOptionData.psd1' } "USERRIGHTS" { $filePath = Join-Path $($PSScriptRoot) -ChildPath 'UserRightsFriendlyNameConversions.psd1' } } if([System.String]::IsNullOrEmpty($filePath) -eq $false) { $returnData = Get-PolicyOptionData -FilePath ($($filePath)).Normalize() } return $returnData } # end function Get-SecurityPolicyData function ConvertTo-LocalFriendlyName { <# .SYNOPSIS Resolves username or SID to a NTAccount friendly name so desired and actual idnetities can be compared .PARAMETER Identity An Identity in the form of a friendly name (testUser1,contoso\testUser1) or SID .EXAMPLE PS C:\> ConvertTo-LocalFriendlyName testuser1 Server1\TestUser1 This example demonstrats converting a username without a domain name specified .EXAMPLE PS C:\> ConvertTo-LocalFriendlyName -Identity S-1-5-21-3084257389-385233670-139165443-1001 Server1\TestUser1 This example demonstrats converting a SID to a frendlyname .LINK https://github.com/dsccommunity/SecurityPolicyDsc/blob/master/source/Modules/SecurityPolicyResourceHelper/SecurityPolicyResourceHelper.psm1 #> [OutPutType([string])] [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [System.String[]] $Identity ) $friendlyNames = @() foreach ($id in $Identity) { $id = ( $id -replace "\*" ).Trim() if ($null -ne $id -and $id -match '^(S-[0-9-]{3,})') { # if id is a SID convert to a NTAccount $friendlyNames += ConvertTo-NTAccount -SID $id -Verbose:$VerbosePreference } else { # if id is an friendly name convert it to a sid and then to an NTAccount $sidResult = ConvertTo-Sid -Identity $id -Verbose:$VerbosePreference if ($sidResult -isnot [System.Security.Principal.SecurityIdentifier]) { continue } $friendlyNames += ConvertTo-NTAccount -SID $sidResult.Value } } return $friendlyNames } # end function ConvertTo-LocalFriendlyName function Test-IdentityIsNull { <# .SYNOPSIS Tests if the provided Identity is null .PARAMETER Identity The identity string to test .LINK https://github.com/dsccommunity/SecurityPolicyDsc/blob/master/source/Modules/SecurityPolicyResourceHelper/SecurityPolicyResourceHelper.psm1 #> [OutputType([bool])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [AllowEmptyCollection()] [AllowEmptyString()] [AllowNull()] [System.String[]] $Identity ) if ($null -eq $Identity -or [System.String]::IsNullOrWhiteSpace($Identity)) { return $true } else { return $false } } # end function Test-IdentityIsNull function ConvertTo-NTAccount { <# .SYNOPSIS Convert a SID to a common friendly name .PARAMETER SID SID of an identity being converted .LINK https://github.com/dsccommunity/SecurityPolicyDsc/blob/master/source/Modules/SecurityPolicyResourceHelper/SecurityPolicyResourceHelper.psm1 #> [OutPutType([string])] [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [System.Security.Principal.SecurityIdentifier[]] $SID ) $result = @() foreach ($id in $SID) { $id = ( $id -replace "\*" ).Trim() $sidId = [System.Security.Principal.SecurityIdentifier]$id try { $result += $sidId.Translate([System.Security.Principal.NTAccount]).value } catch { Write-Error -Message "$($error[0])" } } return $result } # end function ConvertTo-NTAccount function Get-PolicyOptionData { <# .SYNOPSIS Retrieves the Security Option Data to map the policy name and values as they appear in the Security Template Snap-in. .PARAMETER FilePath Path to the file containing the Security Option Data .LINK https://github.com/dsccommunity/SecurityPolicyDsc/blob/master/source/Modules/SecurityPolicyResourceHelper/SecurityPolicyResourceHelper.psm1 #> [OutputType([hashtable])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [Microsoft.PowerShell.DesiredStateConfiguration.ArgumentToConfigurationDataTransformation()] [System.Collections.Hashtable] $FilePath ) return $FilePath } # end function Get-PolicyOptionData function ConvertTo-Sid { <# .SYNOPSIS Converts an identity to a SID to verify it's a valid account .PARAMETER Identity Specifies the identity to convert .NOTES SecurityPolicyDsc/source/Modules/SecurityPolicyResourceHelper/SecurityPolicyResourceHelper.psm1 #> [OutputType([System.Security.Principal.SecurityIdentifier])] [CmdletBinding()] param ( [Parameter()] [System.String] $Identity, [Parameter()] [System.String] $Scope = 'Get' ) $id = [System.Security.Principal.NTAccount]$Identity try { $result = $id.Translate([System.Security.Principal.SecurityIdentifier]) } catch { if ($Scope -eq 'Get') { Write-Verbose -Message ($script:localizedData.ErrorIdToSid -f $Identity) $result = $id } else { throw "$($script:localizedData.ErrorIdToSid -f $Identity)" } } return $result } # end function ConvertTo-Sid Export-ModuleMember -Function "*" |