One of the challenges I’ve had over the years is figuring out a way to add the SQL Service accounts to the “Perform Volume Maintenance Tasks” and “Lock Pages in Memory” local security policy privileges.
Kendra Little published a post a while back that utilized NTRights.exe. Unfortunately, this is not available for Server 2008R2 and Server Core. I have several clients on which I cannot use NTRights.exe.
I developed this function to handle this task. It takes an export of the current local security policy and evaluates it. When it finds the particular privilege you want to add, it will append the account you provided to that file and re-import that setting.
This function was written to accept pipeline and function properly with Confirm, WhatIf, and Verbose common switches. This function must be run locally on the box you are needing to modify the policy and must be run as an administrator to execute the underlying "secedit” command.
Please feel free to share any comments or suggestions you may have.
function Add-LoginToLocalPrivilege { <# .SYNOPSIS Adds the provided login to the local security privilege that is chosen. Must be run as Administrator in UAC mode. Returns a boolean $true if it was successful, $false if it was not. .DESCRIPTION Uses the built in secedit.exe to export the current configuration then re-import the new configuration with the provided login added to the appropriate privilege. The pipeline object must be passed in a DOMAIN\User format as string. This function supports the -WhatIf, -Confirm, and -Verbose switches. .PARAMETER DomainAccount Value passed as a DOMAIN\Account format. .PARAMETER Domain Domain of the account - can be local account by specifying local computer name. Must be used in conjunction with Account. .PARAMETER Account Username of the account you want added to that privilege Must be used in conjunction with Domain .PARAMETER Privilege The name of the privilege you want to be added. This must be one in the following list: SeManageVolumePrivilege SeLockMemoryPrivilege .PARAMETER TemporaryFolderPath The folder path where the secedit exports and imports will reside. The default if this parameter is not provided is $env:USERPROFILE .EXAMPLE Add-LoginToLocalPrivilege -Domain "NEIER" -Account "Kyle" -Privilege "SeManageVolumePrivilege" Using full parameter names .EXAMPLE Add-LoginToLocalPrivilege "NEIER\Kyle" "SeLockMemoryPrivilege" Using Positional parameters only allowed when passing DomainAccount together, not independently. .EXAMPLE Add-LoginToLocalPrivilege "NEIER\Kyle" "SeLockMemoryPrivilege" -Verbose This function supports the verbose switch. Will provide to you several text cues as part of the execution to the console. Will not output the text, only presents to console. .EXAMPLE ("NEIER\Kyle", "NEIER\Stephanie") | Add-LoginToLocalPrivilege -Privilege "SeManageVolumePrivilege" -Verbose Passing array of DOMAIN\User as pipeline parameter with -v switch for verbose logging. Only "Domain\Account" can be passed through pipeline. You cannot use the Domain and Account parameters when using the pipeline. .NOTES The temporary files should be removed at the end of the script. If there is error - two files may remain in the $TemporaryFolderPath (default $env:USERPFORILE) UserRightsAsTheyExist.inf ApplyUserRights.inf These should be deleted if they exist, but will be overwritten if this is run again. Author: Kyle Neier Blog: http://sqldbamusings.blogspot.com Twitter: Kyle_Neier #> #Specify the default parameterset [CmdletBinding(DefaultParametersetName="JointNames", SupportsShouldProcess=$true, ConfirmImpact='High')] param ( [parameter( Mandatory=$true, Position=0, ParameterSetName="SplitNames")] [string] $Domain, [parameter( Mandatory=$true, Position=1, ParameterSetName="SplitNames" )] [string] $Account, [parameter( Mandatory=$true, Position=0, ParameterSetName="JointNames", ValueFromPipeline= $true )] [string] $DomainAccount, [parameter(Mandatory=$true, Position=2)] [ValidateSet("SeManageVolumePrivilege", "SeLockMemoryPrivilege")] [string] $Privilege, [parameter(Mandatory=$false, Position=3)] [string] $TemporaryFolderPath = $env:USERPROFILE ) #Determine which parameter set was used switch ($PsCmdlet.ParameterSetName) { "SplitNames" { #If SplitNames was used, combine the names into a single string Write-Verbose "Domain and Account provided - combining for rest of script." $DomainAccount = "$Domain`\$Account" } "JointNames" { Write-Verbose "Domain\Account combination provided." #Need to do nothing more, the parameter passed is sufficient. } } #Created simple function here so I didn't have to re-type these commands function Remove-TempFiles { #Evaluate whether the ApplyUserRights.inf file exists if(Test-Path $TemporaryFolderPath\ApplyUserRights.inf) { #Remove it if it does. Write-Verbose "Removing $TemporaryFolderPath`\ApplyUserRights.inf" Remove-Item $TemporaryFolderPath\ApplyUserRights.inf -Force -WhatIf:$false } #Evaluate whether the UserRightsAsTheyExists.inf file exists if(Test-Path $TemporaryFolderPath\UserRightsAsTheyExist.inf) { #Remove it if it does. Write-Verbose "Removing $TemporaryFolderPath\UserRightsAsTheyExist.inf" Remove-Item $TemporaryFolderPath\UserRightsAsTheyExist.inf -Force -WhatIf:$false } } Write-Verbose "Adding $DomainAccount to $Privilege" Write-Verbose "Verifying that export file does not exist." #Clean Up any files that may be hanging around. Remove-TempFiles Write-Verbose "Executing secedit and sending to $TemporaryFolderPath" #Use secedit (built in command in windows) to export current User Rights Assignment $SeceditResults = secedit /export /areas USER_RIGHTS /cfg $TemporaryFolderPath\UserRightsAsTheyExist.inf #Make certain export was successful if($SeceditResults[$SeceditResults.Count-2] -eq "The task has completed successfully.") { Write-Verbose "Secedit export was successful, proceeding to re-import" #Save out the header of the file to be imported Write-Verbose "Save out header for $TemporaryFolderPath`\ApplyUserRights.inf" "[Unicode] Unicode=yes [Version] signature=`"`$CHICAGO`$`" Revision=1 [Privilege Rights]" | Out-File $TemporaryFolderPath\ApplyUserRights.inf -Force -WhatIf:$false #Bring the exported config file in as an array Write-Verbose "Importing the exported secedit file." $SecurityPolicyExport = Get-Content $TemporaryFolderPath\UserRightsAsTheyExist.inf #enumerate over each of these files, looking for the Perform Volume Maintenance Tasks privilege [Boolean]$isFound = $false foreach($line in $SecurityPolicyExport) { if($line -like "$Privilege`*") { Write-Verbose "Line with the $Privilege found in export, appending $DomainAccount to it" #Add the current domain\user to the list $line = $line + ",$DomainAccount" #output line, with all old + new accounts to re-import $line | Out-File $TemporaryFolderPath\ApplyUserRights.inf -Append -WhatIf:$false $isFound = $true } } if($isFound -eq $false) { #If the particular command we are looking for can't be found, create it to be imported. Write-Verbose "No line found for $Privilege - Adding new line for $DomainAccount" "$Privilege`=$DomainAccount" | Out-File $TemporaryFolderPath\ApplyUserRights.inf -Append -WhatIf:$false } #Import the new .inf into the local security policy. if ($pscmdlet.ShouldProcess($DomainAccount, "Account be added to Local Security with $Privilege privilege?")) { # yes, Run the import: Write-Verbose "Importing $TemporaryfolderPath\ApplyUserRighs.inf" $SeceditApplyResults = SECEDIT /configure /db secedit.sdb /cfg $TemporaryFolderPath\ApplyUserRights.inf #Verify that update was successful (string reading, blegh.) if($SeceditApplyResults[$SeceditApplyResults.Count-2] -eq "The task has completed successfully.") { #Success, return true Write-Verbose "Import was successful." Write-Output $true } else { #Import failed for some reason Write-Verbose "Import from $TemporaryFolderPath\ApplyUserRights.inf failed." Write-Output $false Write-Error -Message "The import from$TemporaryFolderPath\ApplyUserRights using secedit failed. Full Text Below: $SeceditApplyResults)" } } } else { #Export failed for some reason. Write-Verbose "Export to $TemporaryFolderPath\UserRightsAsTheyExist.inf failed." Write-Output $false Write-Error -Message "The export to $TemporaryFolderPath\UserRightsAsTheyExist.inf from secedit failed. Full Text Below: $SeceditResults)" } Write-Verbose "Cleaning up temporary files that were created." #Delete the two temp files we created. Remove-TempFiles }
About Kyle Neier
Husband of a magnificent woman, father of 5, SQL Server geek, IndyPASS Vice President and Food Guy, DBA automation zealot, amateur Powershell evangelist. Follow Me on Twitter
8 comments:
Factoring said:-
Thanks for sharing how to Adding accounts on Local Security.It tell us hoe to append the account in file and re-import that setting.
factoring invoices said...
Everything is very open and very clear explanation of issues. was truly information. Your website is very useful. Thanks for sharing
When i execute it like this in windows command prompt, i'm always getting a confirmation. How can i execute it without the confirmation?
"powershell.exe C:\SQL-PostBuildConfig\Cloud\Reference\Add-LoginToLocalPrivilege.ps1 'NT Service\MSSQLSERVER' 'SeLockMemoryPrivilege' >> c:\temp\SQLpostBuildConfig_LockPages.log"
Needed to add users to logon as service right.
Although I had an existing script, my version overwrote the existing values which was severe limitation.
Using your code I have added the SeServiceLogonRight and it works perfectly.
Thank you so much for your contribution, much appreciated.
Awesome post. This saved a lot of time being able to do this from powershell instead of rebooting into gui from core.
doesn't work - does nothing. how do you run it? from the command line? from powershell? neither way works for me
Hello Kyle,
Just a quick note to say THANK YOU for posting this function. You coding style and inline commented documentation is absolutely perfect! You have saved myself and an associate quite a few hours of work and testing. This script is extremely valuable for any seasoned DBA that has complete automation at the forefront.
Excellent contribution to the community!
Thank you again Kyle!!
My name is Leah Brown, I'm a happy woman today? I told myself that any loan lender that could change my life and that of my family after having been scammed separately by these online loan lenders, I will refer to anyone who is looking for loan for them. It gave me and my family happiness, although at first I had a hard time trusting him because of my experiences with past loan lenders, I needed a loan of $300,000.00 to start my life everywhere as single mother with 2 children, I met this honest and God fearing online loan lender Gain Credit Loan who helped me with a $300,000.00 loan, working with a loan company Good reputation. If you are in need of a loan and you are 100% sure of paying the loan please contact (gaincreditloan1@gmail.com)
Post a Comment