SamFunctions.ps1

# Copyright 2021 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

<#
.SYNOPSIS
Connect to a SAM server.
.DESCRIPTION
This cmdlet connects to a SAM server for a specified system and access rights.
.PARAMETER ServerName
Specify the target system.
.PARAMETER Access
Specify the access rights on the server.
.INPUTS
None
.OUTPUTS
NtApiDotNet.Win32.Security.Sam.SamServer
.EXAMPLE
Connect-SamServer
Connect to the local SAM server with maximum access.
.EXAMPLE
Connect-SamServer -ServerName "PRIMARYDC"
Connect to the SAM server on the system PRIMARYDC with maximum access.
.EXAMPLE
Connect-SamServer -Access EnumerateDomains
Connect to the local SAM server with EnumerateDomains access.
#>

function Connect-SamServer { 
    [CmdletBinding()]
    param(
        [NtApiDotNet.Win32.Security.Sam.SamServerAccessRights]$Access = "MaximumAllowed",
        [string]$ServerName
    )

    [NtApiDotNet.Win32.Security.Sam.SamServer]::Connect($ServerName, $Access)
}

<#
.SYNOPSIS
Get a domain object from a SAM server.
.DESCRIPTION
This cmdlet opens a domain object from a SAM server. Defaults to returning all accessible domain objects.
.PARAMETER Server
The server the query for the domain.
.PARAMETER Access
Specify the access rights on the domain object.
.PARAMETER InfoOnly
Specify to only get domain information not objects.
.PARAMETER Name
Specify to get domain by name.
.PARAMETER DomainId
Specify to get domain by SID.
.PARAMETER Builtin
Specify to open the builtin domain.
.PARAMETER User
Specify to open the user domain.
.INPUTS
None
.OUTPUTS
NtApiDotNet.Win32.Security.Sam.SamDomain
.EXAMPLE
Get-SamDomain -Server $server
Get all accessible domain objects from the server.
.EXAMPLE
Get-SamDomain -Server $server -InfoOnly
Get all Information only domain from the server.
.EXAMPLE
Get-SamDomain -Server $server -Name "FLUBBER"
Get the FLUBBER domain object from the server.
#>

function Get-SamDomain { 
    [CmdletBinding(DefaultParameterSetName="All")]
    param(
        [Parameter(Mandatory, Position = 0)]
        [NtApiDotNet.Win32.Security.Sam.SamServer]$Server,
        [Parameter(Mandatory, Position = 1, ParameterSetName="FromName")]
        [string]$Name,
        [Parameter(Mandatory, ParameterSetName="FromSid")]
        [NtApiDotNet.Sid]$DomainId,
        [Parameter(Mandatory, ParameterSetName="FromUser")]
        [switch]$User,
        [Parameter(Mandatory, ParameterSetName="FromBuiltin")]
        [switch]$Builtin,
        [Parameter(ParameterSetName="All")]
        [Parameter(ParameterSetName="FromName")]
        [Parameter(ParameterSetName="FromSid")]
        [Parameter(ParameterSetName="FromUser")]
        [Parameter(ParameterSetName="FromBuiltin")]
        [NtApiDotNet.Win32.Security.Sam.SamDomainAccessRights]$Access = "MaximumAllowed",
        [Parameter(Mandatory, ParameterSetName="AllInfoOnly")]
        [switch]$InfoOnly
    )

    if ($InfoOnly) {
        $Server.EnumerateDomains() | ForEach-Object { 
            [PSCustomObject]@{
                Name = $_.Name
                DomainId = $Server.LookupDomain($_.Name)
            }
        }
    } else {
        switch($PSCmdlet.ParameterSetName) {
            "All" {
                $Server.OpenAccessibleDomains($Access) | Write-Output
            }
            "FromName" {
                $Server.OpenDomain($Name, $Access)
            }
            "FromSid" {
                $Server.OpenDomain($DomainId, $Access)
            }
            "FromBuiltin" {
                $Server.OpenBuiltinDomain($Access)
            }
            "FromUser" {
                $Server.OpenUserDomain($Access)
            }
        }
    }
}

<#
.SYNOPSIS
Get a user object from a SAM server.
.DESCRIPTION
This cmdlet opens a user object from a SAM server.
.PARAMETER Domain
Specify the domain to get the user from.
.PARAMETER Access
Specify the access rights on the user object.
.PARAMETER InfoOnly
Specify to only get user information not objects.
.PARAMETER Name
Specify to get user by name.
.PARAMETER Sid
Specify to get user by SID.
.PARAMETER UserId
Specify to get user by ID.
.INPUTS
None
.OUTPUTS
NtApiDotNet.Win32.Security.Sam.SamUser
.EXAMPLE
Get-SamUser -Domain $domain
Get all accessible user objects in the domain.
.EXAMPLE
Get-SamUser -Domain $domain -InfoOnly
Get all Information only users from the server.
.EXAMPLE
Get-SamUser -Domain $domain -Name "ALICE"
Get the ALICE user object from the server.
.EXAMPLE
Get-SamUser -Domain $domain -UserId 500
Get the user object from the server with the user ID of 500.
#>

function Get-SamUser { 
    [CmdletBinding(DefaultParameterSetName="All")]
    param(
        [Parameter(Mandatory, Position = 0)]
        [NtApiDotNet.Win32.Security.Sam.SamDomain]$Domain,
        [Parameter(Mandatory, Position = 1, ParameterSetName="FromName")]
        [string]$Name,
        [Parameter(Mandatory, ParameterSetName="FromSid")]
        [NtApiDotNet.Sid]$Sid,
        [Parameter(Mandatory, ParameterSetName="FromUserId")]
        [uint32]$UserId,
        [Parameter(ParameterSetName="All")]
        [Parameter(ParameterSetName="FromName")]
        [Parameter(ParameterSetName="FromSid")]
        [Parameter(ParameterSetName="FromUserId")]
        [NtApiDotNet.Win32.Security.Sam.SamUserAccessRights]$Access = "MaximumAllowed",
        [Parameter(ParameterSetName="All")]
        [Parameter(ParameterSetName="AllInfoOnly")]
        [NtApiDotNet.Win32.Security.Sam.UserAccountControlFlags]$Flags = 0,
        [Parameter(Mandatory, ParameterSetName="AllInfoOnly")]
        [switch]$InfoOnly
    )

    if ($InfoOnly) {
        $Domain.EnumerateUsers() | ForEach-Object { 
            [PSCustomObject]@{
                Name = $_.Name
                Sid = Get-NtSid -Sddl ($Domain.LookupId($_.RelativeId).Sddl)
            }
        }
    } else {
        switch($PSCmdlet.ParameterSetName) {
            "All" {
                $Domain.OpenAccessibleUsers($Flags, $Access) | Write-Output
            }
            "FromName" {
                $Domain.OpenUser($Name, $Access)
            }
            "FromSid" {
                $Domain.OpenUser($Sid, $Access)
            }
            "FromUserId" {
                $Domain.OpenUser($UserId, $Access)
            }
        }
    }
}

<#
.SYNOPSIS
Get a group object from a SAM server.
.DESCRIPTION
This cmdlet opens a group object from a SAM server.
.PARAMETER Domain
Specify the domain to get the group from.
.PARAMETER Access
Specify the access rights on the group object.
.PARAMETER InfoOnly
Specify to only get group information not objects.
.PARAMETER Name
Specify to get group by name.
.PARAMETER Sid
Specify to get group by SID.
.PARAMETER GroupId
Specify to get group by ID.
.INPUTS
None
.OUTPUTS
NtApiDotNet.Win32.Security.Sam.SamGroup
.EXAMPLE
Get-SamGroup -Domain $domain
Get all accessible group objects in the domain.
.EXAMPLE
Get-SamGroup -Domain $domain -InfoOnly
Get all Information only groups from the server.
.EXAMPLE
Get-SamGroup -Domain $domain -Name "USERS"
Get the USERS group object from the server.
.EXAMPLE
Get-SamGroup -Domain $domain -GroupId 501
Get the group object from the server with the group ID of 501.
#>

function Get-SamGroup { 
    [CmdletBinding(DefaultParameterSetName="All")]
    param(
        [Parameter(Mandatory, Position = 0)]
        [NtApiDotNet.Win32.Security.Sam.SamDomain]$Domain,
        [Parameter(Mandatory, Position = 1, ParameterSetName="FromName")]
        [string]$Name,
        [Parameter(Mandatory, ParameterSetName="FromSid")]
        [NtApiDotNet.Sid]$Sid,
        [Parameter(Mandatory, ParameterSetName="FromId")]
        [uint32]$GroupId,
        [Parameter(ParameterSetName="All")]
        [Parameter(ParameterSetName="FromName")]
        [Parameter(ParameterSetName="FromSid")]
        [Parameter(ParameterSetName="FromId")]
        [NtApiDotNet.Win32.Security.Sam.SamGroupAccessRights]$Access = "MaximumAllowed",
        [Parameter(Mandatory, ParameterSetName="AllInfoOnly")]
        [switch]$InfoOnly
    )

    if ($InfoOnly) {
        $Domain.EnumerateGroups() | ForEach-Object { 
            [PSCustomObject]@{
                Name = $_.Name
                Sid = Get-NtSid -Sddl ($Domain.LookupId($_.RelativeId).Sddl)
            }
        }
    } else {
        switch($PSCmdlet.ParameterSetName) {
            "All" {
                $Domain.OpenAccessibleGroups($Access) | Write-Output
            }
            "FromName" {
                $Domain.OpenGroup($Name, $Access)
            }
            "FromSid" {
                $Domain.OpenGroup($Sid, $Access)
            }
            "FromId" {
                $Domain.OpenGroup($GroupId, $Access)
            }
        }
    }
}

<#
.SYNOPSIS
Get a membership of a group object from a SAM server.
.DESCRIPTION
This cmdlet queries the membership of a group object from a SAM server.
.PARAMETER Group
Specify the group object to get the members from.
.INPUTS
None
.OUTPUTS
NtApiDotNet.Win32.Security.Sam.SamGroupMember[]
.EXAMPLE
Get-SamGroupMember -Group $group
Get members of the group objects.
#>

function Get-SamGroupMember { 
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, Position = 0)]
        [NtApiDotNet.Win32.Security.Sam.SamGroup]$Group
    )

    $Group.GetMembers() | Write-Output
}

<#
.SYNOPSIS
Get a membership of an alias object from a SAM server.
.DESCRIPTION
This cmdlet queries the membership of an alias object from a SAM server.
.PARAMETER Alias
Specify the alias object to get the members from.
.INPUTS
None
.OUTPUTS
NtApiDotNet.Sid[]
.EXAMPLE
Get-SamGroupMember -Alias $alias
Get members of the group objects.
#>

function Get-SamAliasMember { 
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, Position = 0)]
        [NtApiDotNet.Win32.Security.Sam.SamAlias]$Alias
    )

    $Alias.GetMembers() | Write-Output
}

<#
.SYNOPSIS
Get an alias object from a SAM server.
.DESCRIPTION
This cmdlet opens an alias object from a SAM server.
.PARAMETER Domain
Specify the domain to get the alias from.
.PARAMETER Access
Specify the access rights on the alias object.
.PARAMETER InfoOnly
Specify to only get alias information not objects.
.PARAMETER Name
Specify to get alias by name.
.PARAMETER Sid
Specify to get alias by SID.
.PARAMETER GroupId
Specify to get alias by ID.
.INPUTS
None
.OUTPUTS
NtApiDotNet.Win32.Security.Sam.SamAlias
.EXAMPLE
Get-SamAlias -Domain $domain
Get all accessible alias objects in the domain.
.EXAMPLE
Get-SamAlias -Domain $domain -InfoOnly
Get all Information only aliases from the server.
.EXAMPLE
Get-SamAlias -Domain $domain -Name "RESOURCE"
Get the RESOURCE alias object from the server.
.EXAMPLE
Get-SamAlias -Domain $domain -AliasId 502
Get the alias object from the server with the alias ID of 502.
#>

function Get-SamAlias { 
    [CmdletBinding(DefaultParameterSetName="All")]
    param(
        [Parameter(Mandatory, Position = 0)]
        [NtApiDotNet.Win32.Security.Sam.SamDomain]$Domain,
        [Parameter(Mandatory, Position = 1, ParameterSetName="FromName")]
        [string]$Name,
        [Parameter(Mandatory, ParameterSetName="FromSid")]
        [NtApiDotNet.Sid]$Sid,
        [Parameter(Mandatory, ParameterSetName="FromId")]
        [uint32]$AliasId,
        [Parameter(ParameterSetName="All")]
        [Parameter(ParameterSetName="FromName")]
        [Parameter(ParameterSetName="FromSid")]
        [Parameter(ParameterSetName="FromId")]
        [NtApiDotNet.Win32.Security.Sam.SamAliasAccessRights]$Access = "MaximumAllowed",
        [Parameter(Mandatory, ParameterSetName="AllInfoOnly")]
        [switch]$InfoOnly
    )

    if ($InfoOnly) {
        $Domain.EnumerateAliases() | ForEach-Object { 
            [PSCustomObject]@{
                Name = $_.Name
                Sid = Get-NtSid -Sddl ($Domain.LookupId($_.RelativeId).Sddl)
            }
        }
    } else {
        switch($PSCmdlet.ParameterSetName) {
            "All" {
                $Domain.OpenAccessibleAliases($Access) | Write-Output
            }
            "FromName" {
                $Domain.OpenAlias($Name, $Access)
            }
            "FromSid" {
                $Domain.OpenAlias($Sid, $Access)
            }
            "FromId" {
                $Domain.OpenAlias($AliasId, $Access)
            }
        }
    }
}

<#
.SYNOPSIS
Create a new SAM user.
.DESCRIPTION
This cmdlet creates a new SAM user.
.PARAMETER Domain
Specify the domain to create the user in.
.PARAMETER Access
Specify the access rights on the user object.
.PARAMETER Name
Specify to name of the user.
.PARAMETER AccountType
Specify the type of account to create.
.INPUTS
None
.OUTPUTS
NtApiDotNet.Win32.Security.Sam.SamUser
.EXAMPLE
New-SamUser -Domain $domain -Name "bob"
Create the bob user in the domain.
.EXAMPLE
New-SamUser -Domain $domain -Name "FILBERT$" -AccountType Workstation
Create the FILBERT$ computer account in the domain.
#>

function New-SamUser { 
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, Position = 0)]
        [NtApiDotNet.Win32.Security.Sam.SamDomain]$Domain,
        [Parameter(Mandatory, Position = 1)]
        [string]$Name,
        [NtApiDotNet.Win32.Security.Sam.SamAliasAccessRights]$Access = "MaximumAllowed",
        [NtApiDotNet.Win32.Security.Sam.SamUserAccountType]$AccountType = "User"
    )
    $Domain.CreateUser($Name, $AccountType, $Access)
}