Summary: Guest blogger, Jason Hofferle, talks about creating constrained Windows PowerShell endpoints.
Microsoft Scripting Guy, Ed Wilson, is here. Today is the exciting conclusion to Jason Hofferle’s excellent series of articles about Windows PowerShell remoting. I think today’s article is the most important of the bunch – because it illustrates a killer security feature. Here is Jason to tell you about creating constrained Windows PowerShell endpoints.
Jason Hofferle has been an IT professional since 1997. His experience includes enterprise desktop engineering for a Fortune 500 financial institution and Active Directory design for local governments and law enforcement. Jason currently works for the Defense Contract Management Agency, where he implements new technology such as virtual desktop infrastructure. He recently has been speaking about Windows PowerShell at SQL Saturday and IT Pro Camp events in Florida, and he frequently attends the Tampa PowerShell User Group.
Blog: Force Multiplication through IT Automation
Twitter: @jhofferle
In Part Four of this series, Sessions and Implicit Remoting, I talked about PowerShell sessions and implicit remoting, which allows commands to behave like they are being run locally when they are actually being run transparently on a remote system. In the final blog in this series, I’m going to discuss constrained endpoints, which allow me to control exactly what cmdlets can be used when I am connected to a remote computer.
When I use remoting to connect to a computer, I’m connecting to an endpoint. The Get-PSSessionConfiguration cmdlet enables me to view the currently registered endpoints. When I use Set-PSSessionConfiguration with the ShowSecurityDescriptorUI parameter, I can view the permissions for an endpoint. The default Windows PowerShell endpoints only allow access to members of the local administrators group. These permissions can be modified, or entirely new endpoints can be created.
So why would I want to create a new endpoint? It’s useful for delegation, because not only can I allow others to connect to that endpoint without granting them administrative rights to the computer, but I can also control precisely what commands they are allowed to run on that endpoint. Each endpoint can have an associated startup script that runs whenever a connection is made to that endpoint. The startup script can be used to automatically run commands, load modules, or constrain the session to limit what it can be used for.
Let’s say I want to grant my Help Desk staff access to run some commands on a server. First I’m going to create a startup script that will constrain the session. I start by restricting the session to the point where it’s useless, and then expose only what’s required for the session to work properly, with the commands that I want my Help Desk to be able to view.
foreach ($command in Get-Command)
{
$command.Visibility = “private”
}
foreach ($variable in Get-Variable)
{
$variable.Visibility = “private”
}
$ExecutionContext.SessionState.Applications.Clear()
$ExecutionContext.SessionState.Scripts.Clear()
$ExecutionContext.SessionState.LanguageMode = “NoLanguage”
$InitialSessionState =
[Management.Automation.Runspaces.InitialSessionState]::CreateRestricted(
“remoteserver”)
foreach ($proxy in $InitialSessionState.Commands | where { $_.Visibility -eq “Public”})
{
$cmdlet = Get-Command -Type cmdlet -ErrorAction silentlycontinue $proxy.name
if ($cmdlet)
{
$alias = Set-Alias “$($proxy.name)” “$($cmdlet.ModuleName)\$($cmdlet.Name)” -PassThru
$alias.Visibility = “Private”
}
Set-Item “function:global:$($proxy.Name)” $proxy.Definition
}
In Bruce Payette’s book, Windows PowerShell in Action 2nd Edition, he uses the InitialSessionState .NET class as an easy way to expose the cmdlets that are required for the session to function correctly. Up to this point, his code is boilerplate that can be used to constrain any endpoint. Now I can start exposing the commands that I want my Help Desk to see. One way to expose certain cmdlets is to change their visibility back to public.
$allowedCmdlets = @(“Get-Date”,”Format-Wide”)
Get-Command | Where-Object {$allowedCmdlets -contains $_.Name} |
foreach {$_.Visibility = “Public”}
If I want to expose an executable or a script, it needs to be added to the endpoint’s list of allowed applications, by using a different method.
$ipConfig = (Get-Command ipconfig.exe).Definition
$ExecutionContext.SessionState.Applications.Add($ipConfig)
Custom functions can also be defined in the startup script. What’s interesting about this is that the staff connecting to this endpoint will have access to the function, but they won’t be able to use the cmdlets inside the function.
Function Get-ServerInfo
{
$CS = Get-WmiObject -Class Win32_ComputerSystem
$OS = Get-WmiObject -Class Win32_OperatingSystem
$Printer = Get-WmiObject -Class Win32_Printer
$MappedLogicalDisk = Get-WmiObject -Class Win32_MappedLogicalDisk
$Result = New-Object PSObject -Property @{
UserName = $CS.UserName
ComputerName = “$($CS.DNSHostName).$($CS.Domain)”
OSArchitecture = $OS.OSArchitecture
OSName = $OS.Caption
OperatingSystemVersion = $OS.Version
OperatingSystemServicePack = “$($OS.ServicePackMajorVersion).$($OS.ServicePackMinorVersion)”
DefaultPrinter = ($Printer | Where-Object {$_.Default}).Name
TypeOfBoot = $CS.BootupState
LastReboot = $OS.ConvertToDateTime($OS.LastBootUpTime).ToString()
Drive = $MappedLogicalDisk |
Select-Object @{Name=’Drive Letter’;Expression={$_.DeviceID}},
@{Name=’Resource Path’;Expression={$_.ProviderName}}
}
Write-Output $Result
}
With my startup script finished, I can use Register-PSSessionConfiguration to create a new endpoint called HelpDesk.
Register-PSSessionConfiguration –Name HelpDesk –StartupScript C:\StartupScript –Force
Now I can use Set-PSSessionConfiguration to grant access to my Active Directory group HelpDesk to allow them to use remoting commands to connect to the endpoint.
Set-PSSessionConfiguration –Name HelpDesk –ShowSecurityDescriptorUI –Force
Now that the PowerShell Remoting endpoint has been constrained with a startup script, my Help Desk staff can access the endpoint, and they’ll only see the commands that are available to them.
This is also an ideal situation to use implicit remoting because I can provide access to custom functions in a single place, without needing to distribute custom modules and scripts. I can update these commands in a single place. They can be used as if they were local, but I don’t have to worry about staff using an old version of a script.
It’s important to note that PowerShell Remoting is security neutral. My Help Desk now has access to connect to my server; however, they cannot do anything that they couldn’t already do. If they don’t have rights to delete user accounts, I couldn’t provide them access to the Remove-ADUser cmdlet and expect them to have the capability to remove user accounts. Permission-denied errors will still occur, just as if they were using the Active Directory Users and Computer MMC snap-in.
The concept of constrained endpoints is used to great effect with Microsoft Office 365 and hosted Exchange Server. I have the ability to connect to a common endpoint, which exposes only the commands available for me to manage my mailboxes. This gives me the capability to automate my hosted Exchange Server environment, even though it’s completely off my network.
Remoting is truly the killer feature of Windows PowerShell. It’s incredibly useful now, and it has lots of future potential. The WSMan framework is a secure and reliable foundation for Microsoft and non-Microsoft software developers, and hardware manufacturers to build their management tools. Remoting can be used to create solutions today, and it will only get more impressive with the release of Windows PowerShell 3.0 in Windows 8 and Windows Server 2012.
Additional Resources
Administrator’s Guide to Windows PowerShell Remoting
Layman’s Guide to PowerShell 2.0 Remoting
Secrets of PowerShell Remoting
~Jason
Thank you, Jason, for an awesome series on remoting. Join us tomorrow for guest blogger, Will Steele.
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
0 comments