Modules/Start-SCOMAgentMaintenanceMode.ps1

Function�Start-SCOMAgentMaintenanceMode
{
    <#�
            .SYNOPSIS�
            This�function�triggers maintenance mode on the current SCOM agent monitored server. It will prevent to set SCOM management server into maintenance mode.�
            Limitation: Works only with SCOM 2016.

            .PARAMETER��Reason�
            Defined reason for the maintenance mode
 
            .PARAMETER��Comment�
            Optional parameter which can be set to add a comment.
 
            .PARAMETER Duration
            Minutes to put system into mainteance mode

            .EXAMPLE�
            PS�C:\>�Start-SCOMAgentMaintenanceMode -Reason PlannedHardwareInstallation -Comment "Need to change HW" -Duration 60
    #>

    [CmdletBinding()]
    param�(
        [ValidateSet(
                'PlannedOther',
                'UnplannedOther',
                'PlannedHardwareMaintenance',
                'UnplannedHardwareMaintenance',
                'PlannedHardwareInstallation',
                'UnplannedHardwareInstallation',
                'PlannedOperatingSystemReconfiguration',
                'UnplannedOperatingSystemReconfiguration',
                'PlannedApplicationMaintenance',
                'UnplannedApplicationMaintenance',
                'ApplicationInstallation',
                'ApplicationUnresponsive',
                'ApplicationUnstable',
                'SecurityIssue',
                'LossOfNetworkConnectivity'
        )] 
        [Parameter(Mandatory = $false)]
        [string]$Reason = 'PlannedOther',
        [Parameter(Mandatory = $false)]
        [string]$Comment = 'No comment set',
        [Parameter(Mandatory = $true)]
        [double]$Duration 
    )

    Try
    {  
        $MinimumDurationInMins = 5.0 
        $ParamSeparator = '|'
        $CommentSeparator = ':'
        $ExtraTimeInMinutes = 8.0
        $RegistryKey = 'HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\MaintenanceMode'
        $Valid = $null
        $Record = $null

        $Current = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $WindowsPrincipal = [System.Security.Principal.WindowsPrincipal]::new($Current)
        If(!($WindowsPrincipal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator )))
        {
            Write-Warning -Message 'Permission denied. Use elevated permission!'
            Throw
        }
        
        If(Test-MgmtServer) 
        {
            Write-Warning -Message 'This command can run only on Agent Machine'
            Throw 
        }

        $Now = Get-Date
        $d = $Now.AddMinutes($Duration)

        If(!(Check-MMAgent))
        {
            Write-Warning -Message 'SCOM agent is not installed!'
            Throw
        }

        If(($d - $Now).TotalMinutes -lt $MinimumDurationInMins)
        {
            Write-Warning -Message 'Minimum duration is 5 minutes!'
            Throw     
        }
        If(!([string]::IsNullOrEmpty($Comment)))
        {
            $Comment = $Comment.Trim()
        }
           
        $CurrentName = ([System.Security.Principal.WindowsIdentity]::GetCurrent()).Name

        If(!(Test-Path -Path  $RegistryKey))
        {
            New-Item -Path  $RegistryKey -Force
            Set-ItemProperty -Path  $RegistryKey -Name IsValid -Value '-1' 
            Set-ItemProperty -Path  $RegistryKey -Name Record -Value '-1'  
        }

        
        $Valid = Get-ItemProperty -Path  $RegistryKey -Name IsValid 
        $Record = Get-ItemProperty -Path  $RegistryKey -Name Record 

        if($Valid.isValid -eq '-1')
        {
            Set-ItemProperty -Path  $RegistryKey -Name IsValid -Value ''  
            $Valid = $null
        }

        If($Record.Record -eq '-1')
        {
            Set-ItemProperty -Path  $RegistryKey -Name Record -Value ''  
            $Record = $null
        }

        If(!([string]::IsNullOrEmpty($Valid.isValid)) -and !([string]::IsNullOrEmpty($Record.Record)) -and ($Valid.isValid -eq '0' -or $Valid.isValid -eq '1'))
        {
            [Double]$Min = $Record.Record.Split('|')[0]
            [DateTime]$SetDate = $Record.Record.Split('|')[3]
            [DateTime]$Now = Get-Date
            [Double]$RemainMin = ($SetDate-$Now).Minutes
            
            if($RemainMin -gt 0.0)
            {
                $Value = [string]::Concat($Duration,$ParamSeparator,$Reason,$ParamSeparator,$CurrentName,$CommentSeparator,$Comment,$ParamSeparator,$Now.ToString())
                Set-ItemProperty -Path  $RegistryKey -Name Record -Value $Value 
                Set-ItemProperty -Path  $RegistryKey -Name IsValid -Value '1'
            }
            
            $TotalMinutes = ($SetDate.AddMinutes($Min + $ExtraTimeInMinutes) -$Now).TotalMinutes
            If($TotalMinutes -gt 0.0)
            {
                if($Valid.isValid -eq '0')
                {
                    Write-Warning -Message "System is probably in Maintenance Mode. Preferably try after $(($Now.AddMinutes($TotalMinutes)))"
                }
                Else
                {
                    Write-Warning -Message 'Last Maintenance Mode Request pending. Try afterwards.'
                }

                return
            }
            
            $Value = [string]::Concat($Duration,$ParamSeparator,$Reason,$ParamSeparator,$CurrentName,$CommentSeparator,$Comment,$ParamSeparator,$Now.ToString())
            Set-ItemProperty -Path  $RegistryKey -Name Record -Value $Value 
            Set-ItemProperty -Path  $RegistryKey -Name IsValid -Value '1'        
        }
        Else
        {
            $Value = [string]::Concat($Duration,$ParamSeparator,$Reason,$ParamSeparator,$CurrentName,$CommentSeparator,$Comment,$ParamSeparator,$Now.ToString())
            Set-ItemProperty -Path  $RegistryKey -Name Record -Value $Value 
            Set-ItemProperty -Path  $RegistryKey -Name IsValid -Value '1'
        }
    }
        
    Catch
    {
        Write-Warning -Message 'Error!'
    }
}