Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding WinRM Mode #41

Open
wants to merge 6 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DomainManagement/DomainManagement.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@
'Unregister-DMOrganizationalUnit'
'Unregister-DMPasswordPolicy'
'Unregister-DMUser'
'Install-DMJEAEndpoint'
'Set-DMWinRMMode'
)

# Cmdlets to export from this module
Expand Down
107 changes: 60 additions & 47 deletions DomainManagement/en-us/strings.psd1

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

.DESCRIPTION
Register a new name mapping.
Mapped names are used for stringr replacement when invoking domain configurations.
Mapped names are used for string replacement when invoking domain configurations.

.PARAMETER Name
The name of the placeholder to register.
Expand Down
55 changes: 43 additions & 12 deletions DomainManagement/functions/other/Get-DMObjectDefaultPermission.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
<#
.SYNOPSIS
Gathers the default object permissions in AD.

.DESCRIPTION
Gathers the default object permissions in AD.
Uses PowerShell remoting against the SchemaMaster to determine the default permissions, as local identity resolution is not reliable.

.PARAMETER ObjectClass
The object class to look up.

.PARAMETER Server
The server / domain to work with.

.PARAMETER Credential
The credentials to use for this operation.

.EXAMPLE
PS C:\> Get-DMObjectDefaultPermission -ObjectClass user

Expand All @@ -30,12 +30,12 @@
$ObjectClass,

[PSFComputer]
$Server = '<Default>',
$Server = 'localhost',

[PSCredential]
$Credential
)

begin
{
if (-not $script:schemaObjectDefaultPermission) {
Expand Down Expand Up @@ -76,7 +76,7 @@
$acl = [System.DirectoryServices.ActiveDirectorySecurity]::new()
$acl.SetSecurityDescriptorSddlForm($class.defaultSecurityDescriptor)
foreach ($rule in $commonAce) { $acl.AddAccessRule($rule) }

<#
if ($class.lDAPDisplayName -eq 'organizationalUnit') {
$acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule(([System.Security.Principal.NTAccount]'Everyone'), 'DeleteTree, Delete', 'Deny', '00000000-0000-0000-0000-000000000000', 'None', '00000000-0000-0000-0000-000000000000')))
Expand All @@ -103,13 +103,44 @@
return $script:schemaObjectDefaultPermission["$Server"].$ObjectClass
}

#region Process Gathering logic
if ($Server -ne '<Default>') {
#region Prepare parameters

$parameters['ComputerName'] = $parameters.Server
$parameters.Remove("Server")

#endregion Prepare parameters

#Check if running locally and change to NoWinRM mode.
$_winRMMode = $script:WinRMMode.Mode
if($Server.IsLocalhost) {
$_winRMMode = 'NoWinRM'
Write-PSFMessage -Level Verbose -String 'Get-DMObjectDefaultPermission.RunningLocally'
}

try {
#TODO get these messages to work at least in verbose.
Write-PSFMessage -Level Verbose -String 'Get-DMObjectDefaultPermission.Mode' -StringValues $_winRMMode
switch ($_winRMMode) {
'Default' {
$data = Invoke-PSFCommand @parameters -ScriptBlock $gatherScript -ErrorAction Stop
}
'JEA' {
$parameters['ConfigurationName'] = $script:WinRMMode.JEAConfigurationName
Write-PSFMessage -Level Verbose -String 'Get-DMObjectDefaultPermission.JEAConfigurationName' -StringValues $script:WinRMMode.JEAConfigurationName
if($script:WinRMMode.JEAEndpointServer){
$_jeaEndpointServer = $script:WinRMMode.JEAEndpointServer | Resolve-String
$parameters['ComputerName'] = $_jeaEndpointServer
}
Write-PSFMessage -Level Verbose -String 'Get-DMObjectDefaultPermission.JEAEndpointServer' -StringValues $_jeaEndpointServer
$data = Invoke-Command @parameters -ScriptBlock { Get-Dmobjectsdefaultpermissions} -ErrorAction Stop
}
'NoWinRM'{
$data = $gatherScript.Invoke()

}
default {throw "WinRMMode is invalid - $_winRMMode"}
}
}

try { $data = Invoke-PSFCommand @parameters -ScriptBlock $gatherScript -ErrorAction Stop }
catch { throw }
$script:schemaObjectDefaultPermission["$Server"] = @{ }
foreach ($datum in $data) {
Expand Down
223 changes: 223 additions & 0 deletions DomainManagement/functions/other/Install-DMJEAEndPoint.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
function Install-DMJEAEndPoint {
<#
.SYNOPSIS
Installs a new JEA EndPoint.

.DESCRIPTION
Installs a new JEA EndPoint on a target computer.
This is used when checking AD Object default permissions from different
forest with a non-domain admin account.
The EndPoint can be a dedicated computer or a domain controller.

.PARAMETER ComputerName
Name of remote endpoint computer name. Default is localhost.
Although it is supported to provide a WinRM session, during installation the session is broken
and a new one is created, therefore you need to be using an account with admin privilages on
remote computer or supply proper credential.

.PARAMETER Credential
Credential to use. Must have local administrator permissions.

.PARAMETER JEAIdentity
Group/user/gMSA account used in configuration.

.EXAMPLE
PS C:\> Install-DMJEAEndpoint -JEAIdentity Domain\username

Installs JEA endpoint on localhost.

.EXAMPLE
PS C:\> Install-DMJEAEndPoint -ComputerName jeaendpoint.contoso.com -JEAIdentity Domain\username -Credential $creds

Installs JEA endpoint on remote computer using supplied credentials.

#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
[CmdletBinding()]
Param (
[PSFComputer] $ComputerName = (Get-CimInstance -ClassName 'win32_computersystem').DNSHostName+"."+(Get-CimInstance -ClassName 'win32_computersystem').Domain, #FQDN

[PSCredential] $Credential,

[Parameter(Mandatory = $true)]
[string] $JEAIdentity

)

begin {
#region: Utility functions
function New-Session {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')]
[CmdletBinding()]
param ([PSFComputer] $ComputerName, [PSCredential] $Credential)

[PSFComputer] $result = $null
# Are we working on local host?
if ($ComputerName.IsLocalhost) {
$result = $ComputerName
Write-PSFMessage -Level Verbose -String 'Install-DMJEAEndPoint.NewSession.LocalHost'
}
else {
if ($ComputerName.Type -ne 'PSSession') {
$parameters = $PSBoundParameters | ConvertTo-PSFHashtable -Include Credential
$parameters['ComputerName'] = $ComputerName.InputObject

$result = New-PSSession @parameters -ErrorAction Stop
}
else { $result = $ComputerName }
}
$result
}
function Copy-JEAModule {
[CmdletBinding()]
Param ([PSFComputer] $ComputerName, $SourceFolderPath)

if ($ComputerName.IsLocalhost) {
#Running on localhost
$modulesRootPath = "$env:ProgramFiles\WindowsPowerShell\Modules\"
Copy-Item -Path $SourceFolderPath -Destination $modulesRootPath -Recurse -Force -ErrorAction Stop
}
else { # Running on remote computer
$modulesRootPath = Invoke-Command -Session $ComputerName.InputObject -ScriptBlock { "$env:ProgramFiles\WindowsPowerShell\Modules\" }
Copy-Item -ToSession $ComputerName.InputObject -Path $SourceFolderPath -Destination $modulesRootPath -Recurse -Force -ErrorAction Stop
}

}
function Register-JEAEndpoint {
[CmdletBinding()]
Param ([PSFComputer] $ComputerName, $JEAIdentity)

$installResult = [PSCustomObject]@{
Success = $true
Error = $null
}
$installResult = Invoke-PSFCommand -ComputerName $ComputerName -ArgumentList $JEAIdentity -scriptblock {
Param(
$JEAIdentity
)
$result = [PSCustomObject]@{
Success = $true
Error = $null
}
try {

$jeaModulePath = "$env:ProgramFiles\WindowsPowerShell\Modules\"
$jeaModuleSessionConfigurationPath = "$jeaModulePath\JEA_DMJEAModule\1.0.0\sessionconfiguration.pssc"

$SessionConfiguration = Get-Content -Path $jeaModuleSessionConfigurationPath -ErrorAction 'Stop'
$SessionConfiguration -replace '%JEAIdentity%', $JEAIdentity | Set-Content $jeaModuleSessionConfigurationPath -Force -ErrorAction 'Stop'

Import-Module -Name JEA_DMJEAModule -ErrorAction 'Stop'
Register-JeaEndpoint_JEA_DMJEAModule -ErrorAction 'Stop' -WarningAction SilentlyContinue

}
catch {
$result.Success = $false
$result.Error = $_
}
$result
} -ErrorAction SilentlyContinue # We expect null output from here if all goes well and the session is broken

Start-Sleep -Seconds 3 # Wait for the session to report as broken

if($installResult.Success -or $ComputerName.InputObject.State -eq "Broken"){

if (-Not $ComputerName.IsLocalhost -and $ComputerName.Type -eq 'PSSession') { #Close any open sessions
Write-PSFMessage -Level Verbose -String 'Install-DMJEAEndPoint.RunScript.SessionBroken'
Remove-PSSession -Session $ComputerName.InputObject -ErrorAction Ignore -WhatIf:$false -Confirm:$false
}
}
else {throw $installResult.Error}
}
function Test-Installation {
[CmdletBinding()]
Param ([PSFComputer] $ComputerName)

$installResult = Invoke-PSFCommand -ComputerName $ComputerName -scriptblock {
$result = [PSCustomObject]@{
Success = $true
Error = $null
}
try {
if (Get-PSSessionConfiguration -Name 'JEA_DMJEAModule' -ErrorAction Stop) {
# Nothing to do, just leave it result.success as $true
}

}
catch {
$result.Success = $false
$result.Error = $_
}
$result
}
if (-Not $installResult.Success) {
throw $installResult.Error
}
$installResult
}
#endregion: Utility functions
$sourceFolderPath = "$script:moduleroot\internal\JEAEndpoint\JEA_DMJEAModule"
}

process {
$parameters = $PSBoundParameters | ConvertTo-PSFHashtable -Include ComputerName, Credential

if ($ComputerName.IsLocalhost) {$parameters.ComputerName = $ComputerName}

Invoke-PSFProtectedCommand -ActionString 'Install-DMJEAEndPoint.NewSession' -ActionStringValues $ComputerName.InputObject -Target $ComputerName.InputObject -ScriptBlock {

$parameters.ComputerName = New-Session @parameters

} -EnableException $EnableException -PSCmdlet $PSCmdlet -whatif:$false -Confirm:$false
if (Test-PSFFunctionInterrupt) { return }

Invoke-PSFProtectedCommand -ActionString 'Install-DMJEAEndPoint.CopyModule' -Target $ComputerName.ComputerName -ScriptBlock {
Copy-JEAModule -ComputerName $parameters.ComputerName -SourceFolderPath $sourceFolderPath

} -EnableException $EnableException -PSCmdlet $PSCmdlet
if (Test-PSFFunctionInterrupt) { return }

Invoke-PSFProtectedCommand -ActionString 'Install-DMJEAEndPoint.RunScript' -Target $ComputerName.ComputerName -ScriptBlock {
Register-JEAEndpoint -ComputerName $parameters.ComputerName -JEAIdentity $JEAIdentity
} -EnableException $EnableException -PSCmdlet $PSCmdlet
if (Test-PSFFunctionInterrupt) { return }

$parameters.ComputerName = $ComputerName.ComputerName

Invoke-PSFProtectedCommand -ActionString 'Install-DMJEAEndPoint.NewSession' -ActionStringValues $ComputerName.InputObject -Target $ComputerName.InputObject -ScriptBlock {

$parameters.ComputerName = New-Session @parameters

} -EnableException $EnableException -PSCmdlet $PSCmdlet -whatif:$false -Confirm:$false -RetryCount 3 -RetryWait 3s
if (Test-PSFFunctionInterrupt) { return }

Invoke-PSFProtectedCommand -ActionString 'Install-DMJEAEndPoint.TestInstallation' -ActionStringValues $ComputerName.InputObject -Target $ComputerName.InputObject -ScriptBlock {

$installResult = Test-Installation -ComputerName $parameters.ComputerName

} -EnableException $EnableException -PSCmdlet $PSCmdlet -whatif:$false -Confirm:$false
if (Test-PSFFunctionInterrupt) { return }


if ($installResult.success) {
Write-PSFMessage -Level Verbose -String 'Install-DMJEAEndPoint.Success'
[PSCustomObject]@{
PSTypeName = 'DomainManagement.WinRM.Mode'
"Mode" = 'JEA'
"JEAConfigurationName" = 'JEA_DMJEAModule'
"JEAEndpointServer" = "$ComputerName"
}
}
else {
throw $installResult.Error
}

}

End {
if (-Not $ComputerName.IsLocalhost -and $parameters.ComputerName.Type -eq 'PSSession') { #Close any open sessions
Remove-PSSession -Session $parameters.ComputerName.InputObject -ErrorAction Ignore -WhatIf:$false -Confirm:$false
}
}
}
Loading