Check for Admin Credentials in a PowerShell Script

Check for Admin Credentials in a PowerShell Script

  • Comments 8
  • Likes

Summary: Learn how to check for administrative credentials when you run a Windows PowerShell script or command.

Microsoft Scripting Guy, Ed Wilson, is here. Boe Prox is our guest blogger today.

Photo of Boe Prox

Boe Prox is currently a senior systems administrator with BAE Systems. He has been in the IT industry since 2003. He spent the past three years working with VBScript and Windows PowerShell, and he now looks to script whatever he can, whenever he can. He is also a moderator on the Hey, Scripting Guy! Forum. Check out his blog, Learn PowerShell | Achieve More, and also see his current project, the WSUS Administrator module, published on CodePlex.

Imagine that you just finished writing a script for a coworker in your office to run and perform an inventory of the servers in your place of business. You give it to your coworker and start on another project, when about two minutes later you hear this: “Arrrgh! Why did this have to happen!?!” You rush over to his desk and you see it, red (or maybe yellow if you used error handling and Write-Warning) all over his monitor like something out of an IT horror movie.

Image of command output

How many times have you seen this or had a user run into this as a result of not knowing or remembering to run the script or command as an administrator in the console?

How could this have been avoided, you ask? The answer is surprisingly simple, but it is usually overlooked, especially when the pressure is on to put together a script or advanced function in a short amount of time. This sea of errors or warnings could have been avoided by adding a check to make sure the individual that is running the script is an administrator and then perform the appropriate action if the user is not an administrator.

By checking for administrative credentials at the beginning of the script, you can ensure that the user (or even yourself) running the script will have to re-run the script with an alternate administrator account or could be prompted for alternate credentials to continue running the script.

Now why would I want to include this in a script when I know as the writer that this will need to be run as an administrator? Perhaps you are in an environment where you follow the rule of least privilege and are only running as a regular user account. Running a script that performs an inventory of servers on the network will fail rather quickly if not run with an administrator account. Or perhaps you forget to tell your coworker, who really doesn’t understand a lot about Windows PowerShell and just opens the prompt and tries running the script. Whether it is for a simple query or for making changes across your production environment, assuming that the script is going to be run with administrative credentials can lead to a rather annoying problem that will require you to take time to educate the individual about running the script as an administrator. Or it could lead to being asked why you didn’t include some sort of check in the first place.

How you decide to perform this check and the proceeding actions are up to you. For my examples, I am going to show a few different actions that can occur when using an administrator check. What you wish to do for a check is completely up to you, and there really isn’t a wrong way of doing it as long as you ensure that a check is performed along with the action if the check fails. The common line of code that I am going to use to perform the check is:

([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`

        [Security.Principal.WindowsBuiltInRole] "Administrator")

Let’s go ahead and run this while I am an administrator and see what we get:

Image of command output

As you can see, it returns “True,” which shows that I am in fact currently running this as an administrator. Upon further inspection, by piping the output into the Get-Member cmdlet, the type of value being returned is “System.Boolean,” which means that it will work nicely when used in an If statement. This piece of knowledge will come in handy in a little bit.

So now we have our piece of code to determine if the current user context is in fact an administrator. The next piece is to determine what type of action or actions that we will take on this. As I mentioned earlier, there are some different ways you can choose to go with this. I am going to start with a simple check that will cause the script to stop if the user is not an administrator. For the sake of saving space, I am only going to show the lines of code for the check and the subsequent action.

If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`

    [Security.Principal.WindowsBuiltInRole] "Administrator"))

{

    Write-Warning "You do not have Administrator rights to run this script!`nPlease re-run this script as an Administrator!"

    Break

}

Image of command output

Remember how I mentioned that the value returned was a Boolean value? With that, I can easily produce an If statement that determines the course of action if the user is not an administrator (False). With this, the script or command will present the warning to the user and then stop running. Although it doesn’t offer any other options for the user, it sure beats getting crushed by a mound of errors that the script will not run, and you can tailor the message so the user understands what needs to be done to properly run the script.

Let’s try one that gives the user a little more freedom when running a script as a non-administrator. This was written as an advanced function called Test-IsAdmin, and it is available to download from the Script Repository on Microsoft TechNet.

Image of command output

We will offer a choice to continue running the script or command as an administrator or to enter alternate credentials instead. This allows the user to make the decision to continue as a regular user or to continue as an administrator. A warning is given stating that the script or command will potentially fail if it is not run as an administrator. If the user chooses to use alternate credentials, the Get-Credential cmdlet is called and the object is then returned from the function to be used in the script or command. The example below uses a technique called “Splatting” to use that object in a hash table that can then be applied to a given cmdlet—in this case, Get-WMIObject.

$splattable = @{}

$splattable['Class'] = "Win32_OperatingSystem"

$splattable['Computername'] = 'server1'

$admincheck = Test-IsAdmin

If ($admincheck  -is [System.Management.Automation.PSCredential])

{

    $splattable['Credential'] = $admincheck

}

Get-WmiObject @splattable

The If statement checks to see if the returned value from the function is the credential object that is returned after using the Get-Credential cmdlet. If the credential object is returned, it is added into the hash table to be used on the WMI query. Otherwise, the current user credentials will be used with potentially unwanted results.

This is a very basic example of what can be done by using a type of administrator check within your script or command. But what this check can do for you in the long term can be very beneficial—not only for the individuals using the script, but also for yourself. This example also provides the greatest use for cmdlets that are making use of the Credential parameter. You can find out which cmdlets have this parameter by running this command:

Get-Command -type cmdlet | Where {$_.Parameters.Containskey("Credential")} | Select-Object Name

Here are the results:

Add-Computer

Add-Content

Clear-Content

Clear-Item

Clear-ItemProperty

Test-WSMan

Connect-WSMan

Copy-Item

Copy-ItemProperty

Enter-PSSession

Get-Content

Get-Credential

Get-HotFix

Get-Item

Get-ItemProperty

Test-Path

Get-WinEvent

Get-WmiObject

Get-WSManInstance

Invoke-Command

Invoke-Item

Stop-Computer

Invoke-WmiMethod

Invoke-WSManAction

Join-Path

Move-Item

Move-ItemProperty

New-Item

New-ItemProperty

New-PSDrive

New-PSSession

New-Service

New-WebServiceProxy

New-WSManInstance

Register-WmiEvent

Remove-Computer

Remove-Item

Remove-ItemProperty

Remove-WmiObject

Remove-WSManInstance

Rename-Item

Rename-ItemProperty

Resolve-Path

Restart-Computer

Send-MailMessage

Test-Connection

Set-Content

Set-Item

Set-ItemProperty

Set-WmiInstance

Set-WSManInstance

Split-Path

Start-Job

Start-Process

   

Let’s say that your script or command doesn’t make use of any of these cmdlets that have the Credential parameter, and it uses something like .NET classes or COM objects to accomplish some sort of action. Well, the good news is that you can use the Start-Process cmdlet in your code to start a new Windows PowerShell instance and call the script under the new administrative credentials as shown here.

$admincheck = Test-IsAdmin

If ($admincheck -is [System.Management.Automation.PSCredential])

{

    Start-Process -FilePath PowerShell.exe -Credential $admincheck -ArgumentList $myinvocation.mycommand.definition

Break

}

The $myinvocation.mycommand.definition, when placed in the script file, will display the script’s path and file name. Knowing this, I can then add this to the ArgumentList parameter of Start-Process to use when starting Windows PowerShell. I make sure to stop the rest of the script by using the Com objects command so the script does not continue on and possibly throw errors.

Hopefully this helps out those of you who may have been on the fence about performing this kind of check or those that may not have thought about adding this type of check into their scripts. Just like error handling in your script, having an administrative credentials check is something that you should look at implementing in your code, especially if that script will be used by people other than yourself. By doing this, you not only prevent unwanted errors when running your script, but it is a nice practice to get into.

Thank you, Boe, for a great article and for illustrating a cool approach to checking for administrative credentials.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Great article, Boe!

    especially because it addresses my favorite "error handling" topic!

    There are two things, I'd like to know:

    1. Why has the powershell team not included a Test-IsAdmin, Get-CurrentUserRole or a kind of Get-ElevationStatus CmdLet natively into powershell?

    2. How can I know for sure, that my script needs admin rights or to run in elevated mode?

    There are times, I can guess that this is a requirement but a good guess is not always enough, I suppose. If e.g. the -whatif switch could return this kind of information for each statement ... !?

    kind regards, Klaus

  • There's a great suggestion on the connect site to add the capability for a script to trigger a UAC prompt for elevation.

    Then a statement could be added to a script that automatically handles it: #requires -role "administrators"

    connect.microsoft.com/.../add-requires-statement-for-uac-elevation

  • Well Jason ... I must have forgotten it, but it seems like I already voted for that :-)

  • Thanks for the article.

    I think that it is important to note that most cmdlets offering the credentials parameter won't work as one would expect.

    For example, if I use valid alternate credentials with the Copy-Item cmdlet, it fails. That's because the PowerShell FileSystem provider doesn't support alternate credentials. Actually, none of the PowerShell 2.0 providers support the Credential capability as demonstrated by Ed Wilson in a recent post: blogs.technet.com/.../discover-which-powershell-providers-support-credentials.aspx

  • Hi,

    I wanted to connect with you. Seen a couple of your posts. So asking you for your advice.

    Requirement - I have to create an application of the below PowerShell script and run this script in admin mode in SCCM 2012 as a dependency with my UE-V Agent application (this msi package has been tested successfully).

    Now how do I create an application of the below program and run this program in powershell admin mode in SCCM 2012. Should I do it with a small task sequence or should I use simple dependency feature. Request you to please advise.

    Program –

    $exists = Test-Path HKLM:\SYSTEM\CurrentControlSet\Services\CSC

    if ($exists)

    {

    $startvalue = get-itemproperty HKLM:\SYSTEM\CurrentControlSet\Services\CSC | foreach {$_.Start}

    if ($startvalue -eq 4)

    {

    set-itemproperty HKLM:\SYSTEM\CurrentControlSet\Services\CSC -Name Start -Value 1

    set-itemproperty HKLM:\SYSTEM\CurrentControlSet\Services\CscService -Name Start -Value 2

    }

    }

    $exists = Test-Path HKLM:\SYSTEM\CurrentControlSet\Services\CscService

    if ($exists)

    {

    $startvalue = get-itemproperty HKLM:\SYSTEM\CurrentControlSet\Services\CSCService | foreach {$_.Start}

    if ($startvalue -eq 4)

    {

    set-itemproperty HKLM:\SYSTEM\CurrentControlSet\Services\CSCService -Name Start -Value 2

    set-itemproperty HKLM:\SYSTEM\CurrentControlSet\Services\Csc -Name Start -Value 1

    }

    }

  • The seem to not work for a domain account, any suggestions?