Tuesday, 29 April 2014

PowerShell Runas

Have you ever had a PowerShell script where you need to run a command with administrative privileges (under the security context of another user), without being prompted to enter credential information?

Recently I needed to run a SharePoint script under two different security context's. Most of the script needed to run as a farm administrator, while a small section of the script needed to run under the security context of the farm service account.

Ingredients:

Invoke-Command
1 x new PSSession Object
1 x PSCredential Object
1 x set of credentials (a username and password)

You can run a script block using the Invoke-Command cmdlet. The Invoke-Command cmdlet can take a PSSession object as a parameter. Using a PSSession object, you can create a PowerShell session with a different security context (as long as you have the username and password of the different user account) by passing the alternate credentials as a PSCredential object.

It's all very easy, and here's a few examples examples.

Basic PowerShell code to run a script block using alternate credentials:

#Variables to store the username and password for the alternate account            
$SPFarmAccountName = "sp-dev-farm";            
$FarmAccountPassword = "NotMyPswd";            

#Convert the plain text password to a SecureString, required to create the PSCredential object
$FarmAccountPasswordAsSecureString = $FarmAccountPassword | ConvertTo-SecureString -Force -AsPlainText            

#Create the PSCredential object using the alternate users username and password            
#Note that the Domain name has been prepended to the username, using the $env:userdomain variable, which represents the current domain.            
$credential = New-Object System.Management.Automation.PsCredential("$env:userdomain\$SPFarmAccountName",$FarmAccountPasswordAsSecureString)              

#Create a new PowerShell session in the security context of the alternate user, using the PSCredential object we just created            
$farmSvcAccSession = New-PSSession -Credential $credential;            

#Write some text to the PowerShell Window, that prints the username from the current context 
Write-Host "This PowerShell command is running under the current users context, $env:userdomain\$env:username" -f magenta            

#Pass the PSSession object to Invoke-Command, and write some text to the PowerShell Window, that prints the username from the current context of the PSSession object (which will be the security context of the alternate user)            
Invoke-Command -Session $farmSvcAccSession -Script { Write-Host "Hello, this script block is running under the security context of the SharePoint Farm Account, $env:userdomain\$env:username" -f Green; }            

#Write some more text to the PowerShell Window, that shoes the security context has returned to the original user            
Write-Host "And now we return to the current users context, $env:userdomain\$env:username" -f magenta



Run a PowerShell script block using alternate credentials, passing a parameter to the elevated session (in this case, a URL)

$waUrl = "http://portal.dev.local";                        
$SPFarmAccountName = "sp-dev-farm";                        
$FarmAccountPassword = "NotMyPswd";             
            
#Convert the password to a secure string                       
$FarmAccountPasswordAsSecureString = $FarmAccountPassword | ConvertTo-SecureString -Force -AsPlainText                        
            
#Create the credential object            
$credential = New-Object System.Management.Automation.PsCredential("$env:userdomain\$SPFarmAccountName",$FarmAccountPasswordAsSecureString)                          
            
#Create the new session            
$farmSvcAccSession = New-PSSession -Credential $credential;            
                       
Write-Host "This PowerShell command is running under the current users context, $env:userdomain\$env:username" -f magenta                        
            
Invoke-Command -Session $farmSvcAccSession -Script {             
        #Write a message to the console, including the "userdomain\username"            
        #environment variables, to show the change in user security context            
        Write-Host "Hello, this script block is running under the security context of the SharePoint Farm Account, $env:userdomain\$env:username The web URL is"$args[0] -f Green;             
    } -Args $waUrl                        
            
Write-Host "And now we return to the current users context, $env:userdomain\$env:username" -f magenta



Run a PowerShell script block using alternate credentials, passing a URL as a parameter to the elevated session, and then running some SharePoint commands.

$waUrl = "http://portal.dev.local";                        
$SPFarmAccountName = "sp-dev-farm";                        
$FarmAccountPassword = "NotMyPswd";             
            
#Convert the password to a secure string                       
$FarmAccountPasswordAsSecureString = $FarmAccountPassword | ConvertTo-SecureString -Force -AsPlainText                        
            
#Create the credential object            
$credential = New-Object System.Management.Automation.PsCredential("$env:userdomain\$SPFarmAccountName",$FarmAccountPasswordAsSecureString)                          
            
#Create the new session            
$farmSvcAccSession = New-PSSession -Credential $credential;            
            
Write-Host "This PowerShell command is running under the current users context, $env:userdomain\$env:username" -f magenta                        
            
#Invoke a command in the elevated session            
Invoke-Command -Session $farmSvcAccSession -Script {            
        #Add the SharePoint snapin (remember that this is a new PS Session)            
        Add-PSSnapin "Microsoft.SharePoint.PowerShell";            
            
        #Write a message to the console, including the "userdomain\username"            
        #environment variables, to show the change in user security context            
        Write-Host "Hello, this script block is running under the security context of the SharePoint Farm Account, $env:userdomain\$env:username The web URL is"$args[0] -f Green;
                    
        #Get an SPWeb object using the elevated session and do some work!            
        $eweb = Get-SPWeb $args[0];$eweb.SiteAdministrators | ForEach-Object {            
            Write-Host "Removing user $_ from site administrators group." -f green;
        };            
        Write-Host "Just joking! Do you think we're crazy?!" -f yellow;              
    } -Args $waUrl                        
            
Write-Host "And now we return to the current users context, $env:userdomain\$env:username" -f magenta


See Also: