From 7dc1ffc3c546c0dee422bb5df0876b7bab02b235 Mon Sep 17 00:00:00 2001 From: Lord Hepipud Date: Tue, 4 Jan 2022 01:22:40 +0100 Subject: [PATCH] Fixes lookup time for Icinga managed user --- doc/100-General/10-Changelog.md | 1 + .../windows/Get-IcingaWindowsUserConfig.psm1 | 79 +++++++++++++++++++ lib/core/windows/New-IcingaWindowsUser.psm1 | 15 ++-- .../windows/Remove-IcingaWindowsUser.psm1 | 13 +-- lib/core/windows/Test-IcingaManagedUser.psm1 | 21 +---- .../windows/Update-IcingaServiceUser.psm1 | 5 +- 6 files changed, 99 insertions(+), 35 deletions(-) create mode 100644 lib/core/windows/Get-IcingaWindowsUserConfig.psm1 diff --git a/doc/100-General/10-Changelog.md b/doc/100-General/10-Changelog.md index 69d18e3..49ba4c8 100644 --- a/doc/100-General/10-Changelog.md +++ b/doc/100-General/10-Changelog.md @@ -14,6 +14,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic ### Bugfixes * [#379](https://github.com/Icinga/icinga-powershell-framework/issues/379) Fixes memory leak for Icinga for Windows by using a custom function being more aggressive on memory cleanup +* [#394](https://github.com/Icinga/icinga-powershell-framework/issues/394) Fixes lookup time for Icinga managed user for large Active Directory environments by limiting lookup to local system only * [#402](https://github.com/Icinga/icinga-powershell-framework/pull/402) Fixes missing address attribute for REST-Api daemon, making it unable to change the listening address * [#403](https://github.com/Icinga/icinga-powershell-framework/pull/403) Fixes memory leak on newly EventLog reader for CLI event stream * [#407](https://github.com/Icinga/icinga-powershell-framework/pull/407) Removes unnecessary module import inside `Invoke-IcingaNamespaceCmdlets` diff --git a/lib/core/windows/Get-IcingaWindowsUserConfig.psm1 b/lib/core/windows/Get-IcingaWindowsUserConfig.psm1 new file mode 100644 index 0000000..92132f3 --- /dev/null +++ b/lib/core/windows/Get-IcingaWindowsUserConfig.psm1 @@ -0,0 +1,79 @@ +<# +.SYNOPSIS + Will return certain configuration values for specified users by + using the username or SID by doing a local lookup with Get-LocalUser, + in case the Cmdlet is installed +.DESCRIPTION + Will return certain configuration values for specified users by + using the username or SID by doing a local lookup with Get-LocalUser, + in case the Cmdlet is installed. + + Allows to test if a user does exist and if the user is managed by + Icinga for Windows. + + In case both, -UserName and -SID are used, the -SID argument will always be + prioritized and therefor only one argument should be used at the same time. +.PARAMETER UserName + The local username you want to fetch config from +.PARAMETER SID + The SID of a local user you want to fetch config from. This argument + will always be prioritized, even when -UserName is set +.EXAMPLE + PS> Get-IcingaWindowsUserConfig -UserName 'icinga'; +.EXAMPLE + PS> Get-IcingaWindowsUserConfig -SID 'S-1-5-21-1004336348-1177238915-682003330-512'; +#> +function Get-IcingaWindowsUserConfig() +{ + param ( + [string]$UserName = '', + [string]$SID = '' + ); + + if ([string]::IsNullOrEmpty($SID) -And [string]::IsNullOrEmpty($UserName) -eq $FALSE) { + $SID = Get-IcingaUserSID -User $UserName; + } + + $UserConfig = @{ + 'SID' = ''; + 'Name' = ''; + 'FullName' = ''; + 'Caption' = ''; + 'Domain' = (Get-IcingaNetbiosName); + 'Description' = ''; + 'IcingaManagedUser' = $FALSE; + 'UserExist' = $FALSE; + }; + + if ([string]::IsNullOrEmpty($SID) -And [string]::IsNullOrEmpty($UserName)) { + return $UserConfig; + } + + # If we are not running PowerShell 5.0 or later, 'Get-LocalUser' will not be available + # which should always result in "false" for the managed user + if ((Test-IcingaFunction 'Get-LocalUser') -eq $FALSE) { + return $UserConfig; + } + + $UserMetadata = Get-IcingaWindowsUserMetadata; + + try { + $UserData = Get-LocalUser -SID $SID -ErrorAction Stop; + } catch { + return $UserConfig; + } + + $UserConfig.SID = $UserData.SID.Value; + $UserConfig.Name = $UserData.Name; + $UserConfig.FullName = $UserData.FullName; + $UserConfig.Caption = [string]::Format('{0}\{1}', $UserConfig.Domain, $UserData.Name); + $UserConfig.Description = $UserData.Description; + + if ($UserConfig.FullName -eq $UserMetadata.FullName -And $UserConfig.Description -eq $UserMetadata.Description) { + $UserConfig.IcingaManagedUser = $TRUE; + } + + $UserConfig.UserExist = $TRUE; + + return $UserConfig; +} diff --git a/lib/core/windows/New-IcingaWindowsUser.psm1 b/lib/core/windows/New-IcingaWindowsUser.psm1 index 14b4b8d..06efecf 100644 --- a/lib/core/windows/New-IcingaWindowsUser.psm1 +++ b/lib/core/windows/New-IcingaWindowsUser.psm1 @@ -14,17 +14,13 @@ function New-IcingaWindowsUser() } $UserMetadata = Get-IcingaWindowsUserMetadata; - $UserConfig = $null; + $UserConfig = Get-IcingaWindowsUserConfig -UserName $IcingaUser; - $SID = Get-IcingaUserSID -User $IcingaUser; - if ([string]::IsNullOrEmpty($SID) -eq $FALSE) { - $UserConfig = Get-IcingaWindowsInformation -Class 'Win32_UserAccount' -Filter ([string]::Format("SID = '{0}'", $SID)); - } - - if ($null -ne $UserConfig) { + # In case the user exist, we can check if it is a managed user for modifying the login password + if ($UserConfig.UserExist) { # User already exist -> override password - but only if the user is entirely managed by Icinga - if ($UserConfig.FullName -eq $UserMetadata.FullName -And $UserConfig.Description -eq $UserMetadata.Description) { + if ($UserConfig.IcingaManagedUser) { $Result = Start-IcingaProcess -Executable 'net' -Arguments ([string]::Format('user "{0}" "{1}"', $IcingaUser, (ConvertFrom-IcingaSecureString -SecureString (New-IcingaWindowsUserPassword)))); if ($Result.ExitCode -ne 0) { @@ -68,8 +64,7 @@ function New-IcingaWindowsUser() $LocalUserGroup.Add("WinNT://$Env:COMPUTERNAME/$IcingaUser,user") #> - $SID = Get-IcingaUserSID -User $IcingaUser; - $UserConfig = Get-IcingaWindowsInformation -Class 'Win32_UserAccount' -Filter ([string]::Format("SID = '{0}'", $SID)); + $UserConfig = Get-IcingaWindowsUserConfig -UserName $IcingaUser; Write-IcingaConsoleNotice 'User was successfully created.'; diff --git a/lib/core/windows/Remove-IcingaWindowsUser.psm1 b/lib/core/windows/Remove-IcingaWindowsUser.psm1 index 8d0b9a2..3e0d56d 100644 --- a/lib/core/windows/Remove-IcingaWindowsUser.psm1 +++ b/lib/core/windows/Remove-IcingaWindowsUser.psm1 @@ -4,10 +4,14 @@ function Remove-IcingaWindowsUser() $IcingaUser = 'icinga' ); - $SID = Get-IcingaUserSID -User $IcingaUser; + $UserConfig = Get-IcingaWindowsUserConfig -UserName $IcingaUser; - if ((Test-IcingaManagedUser -IcingaUser $IcingaUser) -eq $FALSE) { - Write-IcingaConsoleNotice 'The user "{0}" is not present or not created by Icinga for Windows. Unable to remove user' -Objects $IcingaUser; + if ($UserConfig.UserExist -eq $FALSE -Or $UserConfig.IcingaManagedUser -eq $FALSE) { + if ($UserConfig.UserExist -eq $FALSE) { + Write-IcingaConsoleNotice 'The user "{0}" is not present on this system' -Objects $IcingaUser; + } elseif ($UserConfig.IcingaManagedUser -eq $FALSE) { + Write-IcingaConsoleNotice 'The user "{0}" was not created by Icinga for Windows. Unable to remove user' -Objects $IcingaUser; + } return @{ 'User' = $IcingaUser; @@ -15,8 +19,7 @@ function Remove-IcingaWindowsUser() }; } - $UserConfig = Get-IcingaWindowsInformation -Class 'Win32_UserAccount' -Filter ([string]::Format("SID = '{0}'", $SID)); - $Result = Start-IcingaProcess -Executable 'net' -Arguments ([string]::Format('user "{0}" /DELETE', $UserConfig.Name)); + $Result = Start-IcingaProcess -Executable 'net' -Arguments ([string]::Format('user "{0}" /DELETE', $UserConfig.Name)); if ($Result.ExitCode -ne 0) { Write-IcingaConsoleError 'Failed to delete user "{0}": {1}' -Objects $IcingaUser, $Result.Error; diff --git a/lib/core/windows/Test-IcingaManagedUser.psm1 b/lib/core/windows/Test-IcingaManagedUser.psm1 index c33b65c..707ac74 100644 --- a/lib/core/windows/Test-IcingaManagedUser.psm1 +++ b/lib/core/windows/Test-IcingaManagedUser.psm1 @@ -1,24 +1,11 @@ function Test-IcingaManagedUser() { param ( - [string]$IcingaUser, - [string]$SID + [string]$IcingaUser = '', + [string]$SID = '' ); - if ([string]::IsNullOrEmpty($SID)) { - $SID = Get-IcingaUserSID -User $IcingaUser; - } + $UserConfig = Get-IcingaWindowsUserConfig -UserName $IcingaUser -SID $SID; - if ([string]::IsNullOrEmpty($SID)) { - return $FALSE; - } - - $UserConfig = Get-IcingaWindowsInformation -Class 'Win32_UserAccount' -Filter ([string]::Format("SID = '{0}'", $SID)); - $UserMetadata = Get-IcingaWindowsUserMetadata; - - if ($null -eq $UserConfig -Or $UserConfig.FullName -ne $UserMetadata.FullName -Or $UserConfig.Description -ne $UserMetadata.Description) { - return $FALSE; - } - - return $TRUE; + return $UserConfig.IcingaManagedUser; } diff --git a/lib/core/windows/Update-IcingaServiceUser.psm1 b/lib/core/windows/Update-IcingaServiceUser.psm1 index c4495c8..1608c80 100644 --- a/lib/core/windows/Update-IcingaServiceUser.psm1 +++ b/lib/core/windows/Update-IcingaServiceUser.psm1 @@ -10,9 +10,8 @@ function Update-IcingaServiceUser() return; } - $SID = Get-IcingaUserSID -User $IcingaUser; - $UserConfig = Get-IcingaWindowsInformation -Class 'Win32_UserAccount' -Filter ([string]::Format("SID = '{0}'", $SID)); - $User = New-IcingaWindowsUser -IcingaUser $UserConfig.Name; + $UserConfig = Get-IcingaWindowsUserConfig -UserName $IcingaUser; + $User = New-IcingaWindowsUser -IcingaUser $UserConfig.Name; Set-IcingaServiceUser -User $IcingaUser -Password $Global:Icinga.ServiceUserPassword -Service 'icinga2' | Out-Null; Set-IcingaServiceUser -User $IcingaUser -Password $Global:Icinga.ServiceUserPassword -Service 'icingapowershell' | Out-Null;