Server IP : 85.214.239.14 / Your IP : 13.59.183.77 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /lib/python3/dist-packages/ansible_collections/microsoft/ad/plugins/modules/ |
Upload File : |
#!powershell # Copyright (c) 2022 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) #AnsibleRequires -CSharpUtil Ansible.Basic $spec = @{ options = @{ database_path = @{ type = 'path' } dns_domain_name = @{ type = 'str' } domain_admin_password = @{ no_log = $true required = $true type = 'str' } domain_admin_user = @{ required = $true type = 'str' } domain_log_path = @{ # FUTURE: Add alias for log_path once some time has passed type = 'path' } install_dns = @{ type = 'bool' } install_media_path = @{ type = 'path' } local_admin_password = @{ no_log = $true type = 'str' } read_only = @{ default = $false type = 'bool' } reboot = @{ default = $false type = 'bool' } safe_mode_password = @{ no_log = $true type = 'str' } site_name = @{ type = 'str' } state = @{ choices = 'domain_controller', 'member_server' required = $true type = 'str' } sysvol_path = @{ type = 'path' } } required_if = @( , @('state', 'domain_controller', @('dns_domain_name', 'safe_mode_password')) , @('state', 'member_server', @(, 'local_admin_password')) ) supports_check_mode = $true } $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) $module.Result.reboot_required = $false $module.Result._do_action_reboot = $false # Used by action plugin $databasePath = $module.Params.database_path $dnsDomainName = $module.Params.dns_domain_name $installDns = $module.Params.install_dns $installMediaPath = $module.Params.install_media_path $logPath = $module.Params.domain_log_path $readOnly = $module.Params.read_only $siteName = $module.Params.site_name $state = $module.Params.state $sysvolPath = $module.Params.sysvol_path $domainCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @( $module.Params.domain_admin_user, (ConvertTo-SecureString -AsPlainText -Force -String $module.Params.domain_admin_password) ) if ([System.Environment]::OSVersion.Version -lt [Version]"6.2") { $module.FailJson("microsoft.ad.domain_controller requires Windows Server 2012 or higher") } # short-circuit "member server" check, since we don't need feature checks for this... # role 4/5 - backup/primary DC $win32CS = Get-CimInstance -ClassName Win32_ComputerSystem -Property Domain, DomainRole $isKdc = $win32CS.DomainRole -in @(4, 5) If ($state -eq "member_server" -and -not $isKdc) { $module.ExitJson() } # all other operations will require the AD-DS and RSAT-ADDS features... $requiredFeatures = @("AD-Domain-Services", "RSAT-ADDS") $features = Get-WindowsFeature -Name $requiredFeatures $unavailableFeatures = Compare-Object -ReferenceObject $requiredFeatures -DifferenceObject $features.Name -PassThru if ($unavailableFeatures) { $module.FailJson("The following features required for a domain controller are unavailable: $($unavailableFeatures -join ',')") } $missingFeatures = $features | Where-Object InstallState -NE Installed if ($missingFeatures) { $res = Install-WindowsFeature -Name $missingFeatures -WhatIf:$module.CheckMode $module.Result.changed = $true $module.Result.reboot_required = [bool]$res.RestartNeeded # When in check mode and the prereq was "installed" we need to exit early as # the AD cmdlets weren't really installed if ($module.CheckMode) { $module.ExitJson() } } $lastBootTime = (Get-CimInstance -ClassName Win32_OperatingSystem -Property LastBootUpTime).LastBootUpTime.ToFileTime() if ($state -eq 'domain_controller') { # ensure that domain admin user is in UPN or down-level domain format (prevent hang from https://support.microsoft.com/en-us/kb/2737935) If (-not $domainCredential.UserName.Contains("\") -and -not $domainCredential.UserName.Contains("@")) { $module.FailJson("domain_admin_user must be in domain\user or user@domain.com format") } If ($isKdc) { # FUTURE: implement managed Remove/Add to change domains? If ($dnsDomainName -ne $win32CS.Domain) { $msg = -join @( "The host $env:COMPUTERNAME is a domain controller for the domain $($win32CS.Domain); " "changing DC domains is not implemented" ) $module.FailJson($msg) } } else { $safeModePassword = $module.Params.safe_mode_password | ConvertTo-SecureString -AsPlainText -Force $installParams = @{ Confirm = $false Credential = $domainCredential DomainName = $dnsDomainName Force = $true NoRebootOnCompletion = $true SafeModeAdministratorPassword = $safeModePassword SkipPreChecks = $true WhatIf = $module.CheckMode } if ($databasePath) { $installParams.DatabasePath = $databasePath } if ($logPath) { $installParams.LogPath = $logPath } if ($sysvolPath) { $installParams.SysvolPath = $sysvolPath } if ($installMediaPath) { $installParams.InstallationMediaPath = $installMediaPath } if ($readOnly) { # while this is a switch value, if we set on $false site_name is required # https://github.com/ansible/ansible/issues/35858 $installParams.ReadOnlyReplica = $true } if ($siteName) { $installParams.SiteName = $siteName } if ($null -ne $installDns) { $installParams.InstallDns = $installDns } try { $null = Install-ADDSDomainController @installParams } catch [Microsoft.DirectoryServices.Deployment.DCPromoExecutionException] { # ExitCode 15 == 'Role change is in progress or this computer needs to be restarted.' # DCPromo exit codes details can be found at # https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/deploy/troubleshooting-domain-controller-deployment if ($_.Exception.ExitCode -in @(15, 19)) { $module.Result.reboot_required = $true $module.Result._do_action_reboot = $true } $module.FailJson("Failed to install ADDSDomainController, DCPromo exited with $($_.Exception.ExitCode): $($_.Exception.Message)", $_) } finally { # The Netlogon service is set to auto start but is not started. This is # required for Ansible to connect back to the host and reboot in a # later task. Even if this fails Ansible can still connect but only # with ansible_winrm_transport=basic so we just display a warning if # this fails. if (-not $module.CheckMode) { try { Start-Service -Name Netlogon } catch { $msg = -join @( "Failed to start the Netlogon service after promoting the host, " "Ansible may be unable to connect until the host is manually rebooting: $($_.Exception.Message)" ) $module.Warn($msg) } } } $module.Result.changed = $true $module.Result.reboot_required = $true } } else { # at this point we already know we're a DC and shouldn't be (due to short circuit check)... $assignedRoles = @((Get-ADDomainController -Server localhost).OperationMasterRoles) $localAdminPassword = $module.Params.local_admin_password | ConvertTo-SecureString -AsPlainText -Force # FUTURE: figure out a sane way to hand off roles automatically (designated recipient server, randomly look one up?) If ($assignedRoles.Count -gt 0) { $msg = -join @( "This domain controller has operation master role(s) ({0}) assigned; they must be moved to other " "DCs before demotion (see Move-ADDirectoryServerOperationMasterRole)" -f ($assignedRoles -join ", ") ) $module.FailJson($msg) } # While the cmdlet has -WhatIf, it doesn't seem to work properly. Only run # when not in check mode. if (-not $module.CheckMode) { $uninstallParams = @{ Confirm = $false Credential = $domainCredential Force = $true LocalAdministratorPassword = $localAdminPassword NoRebootOnCompletion = $true } $null = Uninstall-ADDSDomainController @uninstallParams } $module.Result.changed = $true $module.Result.reboot_required = $true } if ($module.Result.reboot_required -and $module.Params.reboot -and -not $module.CheckMode) { # Promoting or depromoting puts the server in a very funky state and it may # not be possible for Ansible to connect back without a reboot is done. If # the user requested the action plugin to perform the reboot then start it # here and get the action plugin to continue where this left off. $module.Result._previous_boot_time = $lastBootTime $shutdownRegPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\AutoLogonChecked' Remove-Item -LiteralPath $shutdownRegPath -Force -ErrorAction SilentlyContinue $comment = 'Reboot initiated by Ansible' $stdout = $null $stderr = . { shutdown.exe /r /t 10 /c $comment | Set-Variable stdout } 2>&1 | ForEach-Object ToString if ($LASTEXITCODE -eq 1190) { # A reboot was already scheduled, abort it and try again shutdown.exe /a $stdout = $null $stderr = . { shutdown.exe /r /t 10 /c $comment | Set-Variable stdout } 2>&1 | ForEach-Object ToString } if ($LASTEXITCODE) { $module.Result.rc = $LASTEXITCODE $module.Result.stdout = $stdout $module.Result.stderr = $stderr $module.FailJson("Failed to initiate reboot, see rc, stdout, stderr for more information") } } $module.ExitJson()