Home » Posts tagged 'Powershell'

Tag Archives: Powershell

How To Create Active Directory SPNs The Easy Way With PowerShell

Using the ActiveDirectorySPN module you can quickly and efficiently build and manage AD SPNs and do so more easily than using the typical tools. This article shows you how to use this PowerShell module to build and manage AD SPNs the easy way.

Active Directory Service Principal Names (SPNs) are a necessary part of AD. They are a way of uniquely defining various instances of services. SPNs have always been confusing to me; I could never remember the syntax when creating one. Who could with a string that looks like this: print/prt1.ntdom.reskit.com:1234/cn=bldg26,dc=ntdom,dc=reskit,dc=com

AD SPNs contain four different attributes in this form: <service type>/<host name>:<port number>/<distinguished name>. Some attributes are required and some are not. I was tired of using legacy tools like setspn.exe to clumsily build these SPNs by trial and error. This is why I decided to build a much more structured—read less error-prone way—of creating Active Directory SPNs. I did this through a new PowerShell module I call ActiveDirectorySPN. Let’s go over how to use this PowerShell module to build and manage AD SPNs.
MORE: All PowerShell Tutorials
MORE: PowerShell Best Practices

Using The ActiveDirectorySPN PowerShell Module

First, you’ll need to download the module and get it imported into your PowerShell session. Once you do this, you’ll have all of the various functions available to you.

The first thing I always do when looking at a new PowerShell module is to see what functions are available inside.

It looks like we’ve got support for both user and computer SPNs.

Next, I’ll run a Get function to see if I receive any errors. Let’s try Get-ADComputerSpn to see if it finds my computer SPNs in my domain.

Great! It found them! It also looks like it’s not representing SPNs like I’m used to (in that big string format). It’s breaking apart the individual components into object properties, which is much easier to understand.

Now that I know I can find computer SPNs, let’s try to create a computer SPN. I’ll refer to the help built into the New-ADComputerSpn function and see if there’s any examples of how to do this.

It looks like there’s a good example associated with this function. Let’s try to create a computer SPN to see if it works. In this example, I’m creating a SPN for the MEMBERSRV1 computer account. There is a LDAP service running on this computer and I’d like to define a hostname of MYHOST to it.

New-ADComputerSpn –ComputerName MEMBERSRV1 –ServiceClass ldap –HostName MYHOST

Now that I’ve created it, let’s use Get-ADComputerSPN and specifically query the MEMBERSRV1computer to check to see if the SPN was actually created.

You can see that it did find the new SPN.
The same can also be done for any user as well. Simply replace the Computer reference in the function names to User. Query for and create the SPNs in the exact same fashion.

If you’ve ever created AD SPNs the old-fashioned way you can see that by using PowerShell and this module the task has become much easier. No longer do you have to create and manage SPNs by long strings but you can leverage the intelligence of PowerShell code to read and create SPNs in a much more structured way.

Source: http://www.tomsitpro.com/articles/powershell-create-active-directory-spns,2-7.html

How To Find And Add DNS Record Permissions With PowerShell

Organizations using Active Directory for their DNS service should take advantage of Windows PowerShell to manage bulk permission changes. This how-to will walk you through finding DNS object ACLs and adding DNS object ACEs.

Active Directory (AD) is an enormously popular directory service from Microsoft. AD provides a plethora of services, including single sign-on (SSO) authentication, group policy configuration management, printer management, and more. One of the requirements of AD is Domain Name System (DNS). AD heavily depends on DNS for many of its core features. Due to this requirement, many organizations also choose AD as their primary DNS service for clients and servers. IT organizations point systems to AD domain controllers for internal (and external) name resolution, which leads to a critical reliance on AD DNS.

When an organization uses AD for their DNS service, their DNS zones are AD-integrated. When this happens, DNS records get moved from being stored in a simple text file to actual Active Directory objects inside of the AD database. This comes with several benefits, such as being able to leverage AD’s robust replication technologies and provide DNS services to geographically dispersed locations, automatic DNS record creation for systems, and much more.

However, this reliance on AD also comes with AD’s object security model, which can sometimes get confusing. Large enterprises can potentially have tens or hundreds of thousands of DNS records, which, if AD-integrated, are all AD objects. If bulk permission changes must be made across these objects, it’s important to know how to properly manage them with Windows PowerShell.

Each DNS record, or AD object, has a familiar Security tab when viewing the Properties.DNS objects follow the same security model as many other common objects in the Microsoft environment including files, folders, registry keys/values, and so on. Each DNS object has an assigned Access Control List (ACL) with numerous Access Control Entries (ACEs) inside it. The ACE is made up of a security identity (a username or group) and a set of various permissions indicating what that security identity can do to that object.

To change these permissions, you can simply open up the DNS management tool, right-click on a DNS record, go to Properties, click the Security tab, and you’re off to the races. But what if you need to retrieve or modify existing permissions, or you need to create new ACEs altogether on many DNS objects at once? The answer is to use PowerShell.

Understanding DNS Objects In AD

Before using PowerShell, you must first understand how AD stores DNS records. When integrating DNS into AD, the DNS objects (or dnsNode objects) are always stored in AD’s root or the RootDSE.

From there, whether the admin chooses domain-wide or forest-wide replication depends on where the dnsNode objects reside.dnsNode objects are stored forest-wide in dnsZone containers located in the path


If they’re stored domain-wide, they would be located at


To find all dnsZone containers, you may use the PowerShell command Get-Item and utilize theActive Directory module’s AD drive.

$DomainName = ‘domain.com’

$AdIntegrationType = ‘Domain’
$DomainDn = (Get-AdDomain).DistinguishedName
Get-Item "AD:DC=$DomainName,CN=MicrosoftDNS,DC=$AdIntegrationType`DnsZones,$DomainDn"

Once you’ve found the dnsZone containers, you can now enumerate dnsNode objects, which represent the records themselves.

$DomainName = ‘domain.com’

$AdIntegrationType = ‘Domain’
$DomainDn = (Get-AdDomain).DistinguishedName
Get-ChildItem "AD:DC=$DomainName,CN=MicrosoftDNS,DC=$AdIntegrationType`DnsZones,$DomainDn"

Finding DNS Object ACLs

By this point, you can simply include PowerShell’s Get-Acl cmdlet to grab the ACLs for each of the objects.

$DomainName = ‘domain.com’

$AdIntegrationType = ‘Domain’
$DomainDn = (Get-AdDomain).DistinguishedName
Get-ChildItem "AD:DC=$DomainName,CN=MicrosoftDNS,DC=$AdIntegrationType`DnsZones,$DomainDn" | foreach {
     Get-Acl -Path “ActiveDirectory:://RootDSE/$($_.DistinguishedName)”

Expand the Access property on the ACL object to dig in a little deeper.

(Get-Acl -Path “ActiveDirectory:://RootDSE/$($_.DistinguishedName)”).Access

Adding DNS Object ACEs

You should now be able to find ACLs on your DNS objects. Now that you know where the objects are and how to retrieve them, it’s possible to append additional ACEs to the objects.

Adding ACEs to ACLs attached to AD objects requires three properties:

  • Security Identifier (SID)
  • Rights (Full Control, Modify, Read, and so on)
  • Type (Allow or Deny)

The first thing you must do is retrieve the SID of the security identity you’ll be adding to this ACE. A security identity is something like an AD user account, computer account, or group. To do this, you’ll use the Get-AdUser cmdlet. One of the properties of the result of this cmdlet is the propertyObjectSID.

Let’s say I’d like to add permission for a user account called abertram. To find the SID of abertram, I can use Get-AdUser in this manner.

$Sid = (Get-ADUser abertram -Properties ObjectSID).ObjectSID.Value

Next, you’ll need to create an object using three parameters: the SID, rights, and the type of permission:


In this instance, I want to give the user account Modify rights to this object:

$AccessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Sid, ‘Modify’, ‘Allow’)

Once I build this object, I can then add it to the existing ACL object I built earlier using Get-ChildItem.


Finally, after my ACL object is built, all that’s left to do is apply the ACE to the object, and we’re done.

Set-Acl -Path "ActiveDirectory:://RootDSE/$($AdObject.DistinguishedName)" -AclObject $Acl

To add this ACE to all records, I build upon my previous code and eventually come to a script that looks like this.

$DomainName = ‘domain.com’

$AdIntegrationType = ‘Domain’
$DomainDn = (Get-AdDomain).DistinguishedName
$Sid = (Get-ADUser abertram -Properties ObjectSID).ObjectSID.Value
$AccessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($Sid, ‘Modify’, ‘Allow’)
Get-ChildItem "AD:DC=$DomainName,CN=MicrosoftDNS,DC=$AdIntegrationType`DnsZones,$DomainDn" | foreach {
     $Acl = Get-Acl -Path

    Set-Acl -Path

"ActiveDirectory:://RootDSE/$($_.DistinguishedName)" -AclObject $Acl

Working with Active Directory object permissions is a little complicated. To truly understand this concept, it’s helpful to know a little about the structure of AD and how objects are organized. Also, once you’re able to understand that DNS records are represented by dnsNode objects in Active Directory and how to access them, the task becomes easier.

Source: http://www.tomsitpro.com/articles/powershell-dns-record-permissions,2-930.html

Create DNS PTR record if A record exists

Create DNS PTR record if A record exists.

This script will help you to have a DNS PTR record for each existing A record in your DNS zone.

If a A record has been created in the DNS zone ($dnsDomainName variable) without a PTR record, the script detect it and the PTR record is created in the correct DNS reverse zone.

Script :

$dnsServer = "dnsServer01.local.net"
$dnsDomainName = "local.net"

function CreatePTR($dnsServer,$reverse_zone,$reverse_ip,$hostname) {
    Invoke-WmiMethod -Name CreateInstanceFromPropertyData -Class MicrosoftDNS_PTRType `
    -Namespace root\MicrosoftDNS -ArgumentList "$reverse_zone","$dnsServer","$reverse_ip","$hostname" `
    -ComputerName $dnsServer

$record_R_list = gwmi -namespace "root\MicrosoftDNS" -class MicrosoftDNS_PTRtype -ComputerName $dnsServer | % {$_.recorddata}
$record_A_list = gwmi -namespace "root\MicrosoftDNS" -class MicrosoftDNS_Atype -ComputerName $dnsServer |select ownername,IPaddress | ? { $_.ownername -like "*.$dnsDomainName" }
$reverse_zone_list = gwmi MicrosoftDNS_Zone -Namespace ‘root\MicrosoftDNS’ -filter "reverse=true" -computer $dnsServer | % {$_.name}

foreach ($a_record in $record_A_list) {
    $hostname = $a_record.ownername+"."
    $ipaddress = $a_record.IPaddress
    if ($record_R_list -notcontains $hostname) {
        Write-Host -NoNewline "The following host does not have a valid reverse record in DNS : " $hostname

        $PingStatus = Gwmi Win32_PingStatus -Filter "Address = ‘$hostname’" | Select-Object StatusCode
        If ($PingStatus.StatusCode -eq 0){
            Write-Host " (online)" -Fore "Green"
            $arr = $ipaddress.split(".")
            $reverse_ip = ($arr -join ‘.’) + ".in-addr.arpa"

            #detect the correct dns reverse lookup zone
            $arr_rvr = $reverse_ip.Split(".")
            $arr_rvr1 = $arr_rvr[1] + "." + $arr_rvr[2] + "." + $arr_rvr[3] + ".in-addr.arpa"
            $arr_rvr2 = $arr_rvr[2] + "." + $arr_rvr[3] + ".in-addr.arpa"
            $arr_rvr3 = $arr_rvr[3] + ".in-addr.arpa"
            if ($reverse_zone_list -contains $arr_rvr1){
                Write-Host $arr_rvr1 " exists in DNS reverse lookup zones"
                Write-Host $reverse_ip
                CreatePTR $dnsServer $arr_rvr1 $reverse_ip $hostname
            elseif ($reverse_zone_list -contains $arr_rvr2){
                Write-Host $arr_rvr2 " exists in DNS reverse lookup zones"
                Write-Host $reverse_ip
                CreatePTR $dnsServer $arr_rvr2 $reverse_ip $hostname
            elseif ($reverse_zone_list -contains $arr_rvr3) {
                Write-Host $arr_rvr3 " exists in DNS reverse lookup zones"
                Write-Host $reverse_ip
                CreatePTR $dnsServer $arr_rvr3 $reverse_ip $hostname
            else {
                Write-Host "Reverse lookup zone does not exist. Cannot create the PTR record"
        Else {
            Write-Host " (offline)"  -Fore "Red"

Source: https://www.shellandco.net/create-dns-ptr-record-if-a-record-exists/

Backup/Restore all DNS zones

Backup/Restore all DNS zones

These scripts backup and restore all DNS zones on specific DNS server (source).
The backup script uses the Powershell cmdlet get-wmiobject to list the DNS zone present in the WMI database and then export each zone using the dnscmd tool.
The restore script uses the dnscmd tool to create the zone and his content.

Useful link on how to export and import AD integrated zone files.

Backup script :

# Script_Name : DNS_Backup.ps1
# Description : backup all DNS Zones defined on a Windows 2008 DNS Server
# Requirements : Windows 2008/R2 + DNS Management console Installed
# Version : 0.4 – Intergrated comments from Jeffrey Hicks
# Date : October 2011
# Created by Griffon
#——————————————————————————————-##– DEFINE VARIABLE——#
# Get Name of the server with env variable

$DNSSERVER=get-content env:computername

#—Define folder where to store backup  —–#

#—Define file name where to store Dns Settings
$StrFile=Join-Path $BkfFolder “input.csv”

#—-Check if folder exists. if exists, delete contents–#
if (-not(test-path $BkfFolder)) {
new-item $BkfFolder -Type Directory | Out-Null
} else {

Remove-Item $BkfFolder”\*” -recurse

#– Line wrapped should be only one line –#
$List = get-WmiObject -ComputerName $DNSSERVER
-Namespace root\MicrosoftDNS -Class MicrosoftDNS_Zone

#—-Export information into input.csv file —#
#– Line wrapped should be only one line –#
$list | Select Name,ZoneType,AllowUpdate,@{Name=”MasterServers”;Expression={$_.MasterServers}},
DsIntegrated | Export-csv $strFile -NoTypeInformation

#— Call Dnscmd.exe to export dns zones
$list | foreach {
$cmd=”dnscmd {0} /ZoneExport {1} {2}” -f $DNSSERVER,$_.Name,$path
Invoke-Expression $cmd

# End of Script


Restore script :

# Script_Name : RestoreDNS.ps1
# Description : Perform Restore of DNS Zones of a Windows 2008 DNS SErver
# Requirements : Windows 2008/R2 + DNS Management console Installed
# Version : 0.4
# Date : October 2011
# Created by Griffon
#———————————————————————–##– DEFINE VARIABLE——#
# Get Name of the server with env variable

$DNSSERVER=gc env:computername



#—Define file name where Dns Settings are Stored

$StrFile=Join-Path $BkfFolder “input.csv”


$Zone=import-csv $StrFile
$Zone | foreach {


#—– Checking if AD Integrated or Not ——-#if ($_.DsIntegrated -eq $True) {
Switch ($_.ZoneType)
1 {
#—– Need to Create Zone As Primary to get all records imported ——-#
$cmd0=”dnscmd {0} /ZoneAdd {1} /primary /file {2} /load” -f $DNSSERVER,$Zone,$path
Invoke-Expression $cmd0
$cmd1=”dnscmd {0} /ZoneResetType {1} /dsprimary” -f $DNSSERVER,$Zone

3 { $cmd1=”dnscmd {0} /ZoneAdd {1} /dsstub {2} /load” -f $DNSSERVER,$Zone,$IP }
4 { $cmd1=”dnscmd {0} /ZoneAdd {1} /dsforwarder {2} /load” -f $DNSSERVER,$Zone,$IP }
} else {

Switch ($_.ZoneType)
1 {$cmd1=”dnscmd {0} /ZoneAdd {1} /primary /file {2} /load” -f $DNSSERVER,$Zone,$path}
2 {$cmd1=”dnscmd {0} /ZoneAdd {1} /secondary {2}” -f $DNSSERVER,$Zone,$IP }
3 {$cmd1=”dnscmd {0} /ZoneAdd {1} /stub {2}” -f $DNSSERVER,$Zone,$IP }
4 {$cmd1=”dnscmd {0} /ZoneAdd {1} /forwarder {2}” -f $DNSSERVER,$Zone,$IP }

#Restore DNS Zones
Invoke-Expression $cmd1

Switch ($_.AllowUpdate)
#No Update
0 {$cmd2=”dnscmd /Config {0} /allowupdate {1}” -f $Zone,$Update}
#Secure and non secure
1 {$cmd2=”dnscmd /Config {0} /allowupdate {1}” -f $Zone,$Update}
#Only Secure Updates
2 {$cmd2=”dnscmd /Config {0} /allowupdate {1}” -f $Zone,$Update}


#Reset DNS Update Settings
Invoke-Expression $cmd2


# End of Script

Source: https://www.shellandco.net/backuprestore-all-dns-zones/

Get all DCs in a forest and resolve hostname to IP address

With this script, you will be able to get all DCs in a forest and resolve hostname to IP address. The pre-requesite to run this script is to install the DNS Shell cmdlets (http://dnsshell.codeplex.com/)

Script :

$myForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$hosts = $myforest.Sites | % { $_.Servers } | select Name
foreach ($hostname in $hosts) {
Get-Dns $hostname.Name | select Answer

Source: https://www.shellandco.net/get-all-dcs-in-a-forest-and-resolve-hostname-to-ip-address/

Copy the group members to another group

This script copy the group members to another group. You have the choice between Microsoft Active Directory cmdlet or the Quest Active Directory cmdlet.

Script (with Microsoft Active Directory module loaded : import-module activedirectory) :

$Source_Group = "CN=SourceGroupName,OU=Groups,DC=domain,DC=com"
$Destination_Group = "CN=DestinationGroupName,OU=Groups,DC=domain,DC=com"
$Target = Get-ADGroupMember $Source_Group
foreach ($Person in $Target) {
    add-ADGroupMember -identity $Destination_Group -members $Person.distinguishedName

Source: https://www.shellandco.net/copy-the-group-members-to-another-group/

Count the object types in the Active Directory forest

You can use this script if you want to count the object types in the Active Directory forest. The script performs these steps:

  • list the domain name in the current Active Directory forest
  • get the Active Directory forest level mode
  • for each domain, the script counts the following object types :
    • User
    • Contact
    • Security group
    • Distribution lists
    • Computer
    • Server
    • Domain Controller
    • Organizational unit
    • Group policy
  • the result output is sent to a csv file located in the folder “c:\temp”

#Get Domain List
$objForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$DomainList = @($objForest.Domains | Select-Object Name,DomainMode)
$fct_lvl_mode_Forest = $objForest.ForestMode

$array = @()
#Act on each domain
foreach($Domain in $DomainList){
    $Domain_name = $Domain.Name
    $fct_lvl_mode_Domain = $Domain.DomainMode
    Write-Host "Checking $Domain_name" -fore red
    $ADsPath = [ADSI]"LDAP://$Domain_name"
    $objSearcher = New-Object System.DirectoryServices.DirectorySearcher($ADsPath)
    $objSearcher.Pagesize = 100000
    $objSearcher.SearchScope = "Subtree"

    $objSearcher.Filter = "(&(objectCategory=person)(objectClass=user))"
     $colResults = $objSearcher.FindAll()
    $cnt_user = $colResults.count

    $objSearcher.Filter = "(objectClass=contact)"
     $colResults = $objSearcher.FindAll()
    $cnt_contact = $colResults.count

    #Security Group
    $objSearcher.Filter = "(groupType:1.2.840.113556.1.4.803:=2147483648)"
     $colResults = $objSearcher.FindAll()
    $cnt_group = $colResults.count

    #Distribution Group
    $objSearcher.Filter = "(&(objectCategory=group)(!(groupType:1.2.840.113556.1.4.803:=2147483648)))"
     $colResults = $objSearcher.FindAll()
    $cnt_dl = $colResults.count

    $objSearcher.Filter = "(&(objectCategory=computer)(!(operatingSystem=*server*)))"
     $colResults = $objSearcher.FindAll()
    $cnt_computer = $colResults.count

    $objSearcher.Filter = "(&(objectCategory=computer)(operatingSystem=*server*)(!(userAccountControl:1.2.840.113556.1.4.803:=8192)))"
     $colResults = $objSearcher.FindAll()
    $cnt_server = $colResults.count

    $objSearcher.Filter = "(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))"
     $colResults = $objSearcher.FindAll()
    $cnt_dc = $colResults.count

    $objSearcher.Filter = "(objectCategory=organizationalUnit)"
     $colResults = $objSearcher.FindAll()
    $cnt_ou = $colResults.count

    $objSearcher.Filter = "(objectCategory=groupPolicyContainer)"
     $colResults = $objSearcher.FindAll()
    $cnt_gpo = $colResults.count

    $Properties = @{domain=$Domain_name;domain_mode=$fct_lvl_mode_Domain;forest_mode=$fct_lvl_mode_Forest;user=$cnt_user;contact=$cnt_contact;group=$cnt_group;dl=$cnt_dl;workstation=$cnt_computer;server=$cnt_server;dc=$cnt_dc;ou=$cnt_ou;gpo=$cnt_gpo}
    $Newobject = New-Object PSObject -Property $Properties
    $array +=$newobject

$array | ConvertTo-Csv -NoTypeInformation -Delimiter ";" | Foreach-Object {$_ -replace ‘"’, ”} | Out-File "c:\temp\ad_info.csv" -Encoding ASCII

ReferenceActive Directory Service Interfaces
Active Directory Service Interfaces (ADSI) is a set of COM interfaces used to access the features of directory services from different network providers. ADSI is used in a distributed computing environment to present a single set of directory service interfaces for managing network resources. Administrators and developers can use ADSI services to enumerate and manage the resources in a directory service, no matter which network environment contains the resource.
ADSI enables common administrative tasks, such as adding new users, managing printers, and locating resources in a distributed computing environment.

ADSI Edit (adsiedit.msc)
Active Directory® Service Interfaces Editor (ADSI Edit) is a Lightweight Directory Access Protocol (LDAP) editor that you can use to manage objects and attributes in Active Directory. ADSI Edit (adsiedit.msc) provides a view of every object and attribute in an Active Directory forest. You can use ADSI Edit to query, view, and edit attributes that are not exposed through other Active Directory Microsoft Management Console (MMC) snap-ins: Active Directory Users and Computers, Active Directory Sites and Services, Active Directory Domains and Trusts, and Active Directory Schema.

Source: https://www.shellandco.net/count-the-object-types-in-the-active-directory-forest/