Monday, March 09, 2020

Deploying and Managing Active Directory with PowerShell 7

I am in the process of writing a book on PowerShell 7 and one chapter is devoted to deploying and managing Active Directory. When I began looking at doing the book, it was early days for PowerShell core, and coverage was kind of poor. Early on, the AD modules did not seem to be particularly usable from within what was PowerShell Core 6.x. But having completed the chapter using PowerShell 7 RC3 and RTM, I am pleased to find that AD deployment and management works well with  PowerShell 7 (and VS Code).


PowerShell 7 is based on .NET Core 3.1, whereas Windows PowerShell is based in the full .NET Framework. This means that some modules, particularly those below the System32 folder, do not work in PowerShell 7 natively.

The PowerShell team's compatibility solution for older modules is to leverage remoting. When you attempt to load a non-compatible module, Import-Module creates a remoting session into a Windows PowerShell endpoint. Then, using implicit remoting, it imports functions into the calling session. Thus you can use the commands in those modules as if they were directly supported.

The remoting session created uses the same Process transport that it uses to create background jobs. So it's relatively efficient and doesn't require WinRM. If you load multiple modules via compatibility, PowerShell just creates one session. And if you want to enter the session and look around that too is easy to do.

What DOESN'T Work?

This compatibility solution works very well but is not a universal get out of jail card. A very small number of modules will never work either directly or via the compatibility solution. Because the solution depends on remoting, some modules do not work due to object serialization that occurs when implicit remoting is invoked. The only solution is for the relevant product team to redevelop their modules (and for at least one module, Update Services, this would require a complete re-engineering of the module). At the time of writing, there are but three modules that simply do not and will not work in PowerShell 7.

The Update Services module, which you would use to manage WSUS, does not work. With this module, you use object methods to perform administrative functions (unlike almost all other modules that deliver commands or cmdlets rather than offering object Methods). The scripting model used by Update Services is reminiscent of COM programming where you instantiate an object and use its methods. A redesign to use command/cmdlets would be a great solution.

When you use the compatibility solution with this module, the methods are stripped off so you can't really do anything with the objects. The Update Service module also uses SOAP to communicate with the WSUS Server, and this is not supported in .NET Core. For that reason, without a complete redesign of the module (either to not use methods or to port the module to .NET Core and eliminate SOAP), you must manage WSUS using Windows PowerShell.

In the early Preview versions of the compatibility feature, had you tried to use some modules, you received hard to understand error messages (and of course, those object methods you need were missing.) Additionally, the error messages that were generated were not actionable and of no value.

The user experience was rather poor, even if you understood the issue. To avoid a bad user experience to this otherwise useful solution, some modules are blocked from being imported. If you try to import the UpdateServices, Import-Module raises and error. This is a much better user experience given that a few modules simply do not work in PowerShell.

The Import-Module stops you from loading modules as defined in the powershell.config.json file in PowerShell's home folder. This file also holds a list of Experimental Features which you have enabled. In my daily build folder, the file looks like this:
{ "ExperimentalFeatures": [ "PSCommandNotFoundSuggestion", "PSCultureInvariantReplaceOperator", "PSImplicitRemotingBatching", "PSNullConditionalOperators", "Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace", "PSDesiredStateConfiguration.InvokeDscResource" ], "WindowsPowerShellCompatibilityModuleDenyList": [ "PSScheduledJob", "BestPractices", "UpdateServices" ], "Microsoft.PowerShell:ExecutionPolicy": "RemoteSigned" }
As you can see there are only three modules that are simply not going to work in PowerShell 7. For me, this is pretty good going and, at least for WIndows, gives IT Pros little reason not to move forward.

For those modules that DO work in the compatibility solution, there is one other minor issue you might trip over. The display XML that is used to display objects returned from a command. This display XML is not present in your PowerShell session by default which means default output may not be as nice as you might like for example when viewing the windows feature objects returned by Get-WIndowsFeature. Fortunately, there is a very simple workaround for that - just manually load the display XML.

So What About AD?

In terms of Active Directory, there are three modules that you need to use:
  • Server Manager module - this module enables you to add the AD DS feature to a server (which adds the other AD modules).
  • AD Deployment module - this module enables you to create new DCs (effectively do the job of DCPromo).
  • Active Directory module -   this module allows you to create, update, and delete objects in the AD Database such as adding users, updating groups, etc
The Server Manager module is supported by the compatibility solution and all the key commands work as they should. When you load this module, Import-Module does generate a warning message to warn you that this module is being imported via the compatibility solution. Once the module is imported, you can add, get, and remove windows features.

One small issue with this module is that the display XML that enables the output from Get-WindowsFeature to look so nice is not present by default in your PowerShell session. If this matters to you, you can deal with this by explicitly importing the display XML like this
Update-FormatData -PrependPath C:\Windows\System32\WindowsPowerShell\v1.0\modules\servermanager\feature.format.ps1xml
The AD Deployment module is also supported via the compatibility solution and was fully functional. I tested the following scenarios
  • Create a Forest Root DC
  • Create a replica DC in the first domain
  • Create DC(s) in a child Domain
  • Create an additional Forest and implement a cross-forest trust.
  • Create, update and remove OU, User, Computer, and group objects and manage group membership as well as other admin tasks (eg change password). 
The only relatively minor problem with all of this was that there are no commands to set up the cross-forest trust. To set up the trust, you just use the .NET objects and these work in .NET Core. But of course, that wasn't possible using the module in Windows PowerShell either!

The Active Directory module was one of the first modules to be ported and seems to work. I have not tested every scenario, but adding/modifying/removing users/groups/computers, managing OU contents and the like all work just as you would expect.

You can see the PowerShell 7 scripts that I developed in Github: Note that these scripts are currently being developed so may change before the book is published/


PowerShell 7 both now with RC2 and when it is fully released supports deploying and managing AD forests and domains. There is a minor issue with display XML and Get-WinowsFeature which has an easy workaround. The key point is that I was able to deploy multiple forests and manage the objects inside the AD as well as with Windows PowerShell.

If you are a Windows IT Pro and use Windows PowerShell to manage Windows services and applications, you really should try PowerShell 7. It's easy to download and use and you can run it side by side with Windows PowerShell. That can enable you to enjoy the new features where you can but fall back to Windows PowerShell when you need to

What are you waiting for?

1 comment:

Joerg Hochwald said...

Great article, very useful.
But one minor comment about the .NET Core version: shouldn’t it be .NET Core 3.2 instead of .NET Core 7?