PSCCMClient.psm1

#Region '.\Enum\CMLogType.ps1' 0
enum CMLogType {
    FullCMTrace
    SimpleCMTrace
}
#EndRegion '.\Enum\CMLogType.ps1' 5
#Region '.\Enum\Severity.ps1' 0
enum Severity {
    None
    Informational
    Warning
    Error
}
#EndRegion '.\Enum\Severity.ps1' 7
#Region '.\Classes\CMLogEntry.ps1' 0
class CMLogEntry {
    [string]$Message
    [Severity]$Type
    [string]$Component
    [int]$Thread
    [datetime]$Timestamp
    hidden [string]$Offset

    CMLogEntry() {
    }

    CMLogEntry([string]$Message, [Severity]$Type, [string]$Component, [int]$Thread) {
        $this.Message = $Message
        $this.Type = $Type
        $this.Component = $Component
        $this.Thread = $Thread
    }

    [void]ResolveTimestamp([array]$LogLineSubArray, [CMLogType]$Type) {
        [string]$DateString = [string]::Empty
        [string]$TimeString = [string]::Empty
        [string]$TimeStringRaw = [string]::Empty

        try {
            switch ($Type) {
                FullCMTrace {
                    $DateString = $LogLineSubArray[3]
                    $TimeStringRaw = $LogLineSubArray[1]
                    $TimeString = $TimeStringRaw.Substring(0, 12)
                }
                SimpleCMTrace {
                    $DateTimeString = $LogLineSubArray[1]
                    $DateTimeStringArray = $DateTimeString.Split([char]32, [System.StringSplitOptions]::RemoveEmptyEntries)
                    $DateString = $DateTimeStringArray[0]
                    $TimeStringRaw = $DateTimeStringArray[1]
                    $TimeString = $TimeStringRaw.Substring(0, 12)
                }
            }
        }
        catch {
            if ($null -eq $DateString) {
                Write-Warning "Failed to split DateString [LogLineSubArray: $LogLineSubArray] [Error: $($_.Exception.Message)]"
            }
            elseif ($null -eq $TimeString) {
                Write-Warning "Failed to split TimeString [LogLineSubArray: $LogLineSubArray] [Error: $($_.Exception.Message)]"
            }
        }
        $DateStringArray = $DateString.Split([char]45)

        $MonthParser = $DateStringArray[0] -replace '\d', 'M'
        $DayParser = $DateStringArray[1] -replace '\d', 'd'

        $DateTimeFormat = [string]::Format('{0}-{1}-yyyyHH:mm:ss.fff', $MonthParser, $DayParser)
        $DateTimeString = [string]::Format('{0}{1}', $DateString, $TimeString)
        try {
            $This.Timestamp = [datetime]::ParseExact($DateTimeString, $DateTimeFormat, $null)
            # try{
                $this.Offset = $TimeStringRaw.Substring(12, 4)
            # }
            # catch {
                # $this.Offset = "+000"
            # }
        }
        catch {
            Write-Warning "Failed to parse [DateString: $DateString] [TimeString: $TimeString] with [Parser: $DateTimeFormat] [Error: $($_.Exception.Message)]"
        }
    }

    [bool]TestTimestampFilter([datetime]$TimestampGreaterThan, [datetime]$TimestampLessThan) {
        return $this.Timestamp -ge $TimestampGreaterThan -and $this.Timestamp -le $TimestampLessThan 
    }

    [string]ConvertToCMLogLine() {
        return [string]::Format('<![LOG[{0}]LOG]!><time="{1}{2}" date="{3}" component="{4}" context="" type="{5}" thread="{6}" file="">'
            , $this.Message
            , $this.Timestamp.ToString('HH:mm:ss.fff')
            , $this.Offset
            , $this.Timestamp.ToString('MM-dd-yyyy')
            , $this.Component
            , [int]$this.Type
            , $this.Thread)
    }
}
#EndRegion '.\Classes\CMLogEntry.ps1' 84
#Region '.\Private\Convert-FunctionToString.ps1' 0
function Convert-FunctionToString {
    param(
        [Parameter(Mandatory = $True)]
        [string[]]$FunctionToConvert
    )
    $AllFunctions = foreach ($FunctionName in $FunctionToConvert) {
        try {
            $Function = Get-Command -Name $FunctionName -CommandType Function -ErrorAction Stop
        }
        catch {
            Write-Error "Failed to find the specified function [Name = '$FunctionName']"
            continue
        }
        $ScriptBlock = $Function.ScriptBlock
        if ($null -ne $ScriptBlock) {
            [string]::Format("`r`nfunction {0} {{{1}}}", $FunctionName, $ScriptBlock)
        }
        else {
            Write-Error "Function $FunctionName does not have a Script Block and cannot be converted."
        }
    }
    [string]::Join("`r`n", $AllFunctions)
}
#EndRegion '.\Private\Convert-FunctionToString.ps1' 24
#Region '.\Private\ConvertFrom-CCMCodeStringToObject.ps1' 0
function ConvertFrom-CCMCodeStringToObject {
    # TODO - Add help
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
            Position = 0)]
        [ValidateNotNullOrEmpty()]
        [Alias('string')]
        [string]$inputString
    )
    $data = [System.Convert]::FromBase64String($inputString)
    $MemoryStream = [System.IO.MemoryStream]::new()
    $MemoryStream.Write($data, 0, $data.length)
    $null = $MemoryStream.Seek(0, 0)
    $streamReader = [System.IO.StreamReader]::new([System.IO.Compression.GZipStream]::new($MemoryStream, [System.IO.Compression.CompressionMode]::Decompress))
    $decompressedData = ConvertFrom-CliXml ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($($streamReader.ReadToEnd()))))
    return $decompressedData
}
#EndRegion '.\Private\ConvertFrom-CCMCodeStringToObject.ps1' 20
#Region '.\Private\ConvertFrom-CLIXml.ps1' 0
function ConvertFrom-CliXml {
    # TODO - Add help
    param (
        [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$InputObject
    )
    begin {
        $OFS = "`n"
        [String]$xmlString = ""
    }
    process {
        $xmlString += $InputObject
    }
    end {
        $Type = [PSObject].Assembly.GetType('System.Management.Automation.Deserializer')
        $ctor = $Type.GetConstructor('instance,nonpublic', $null, @([xml.xmlreader]), $null)
        $StringReader = [System.IO.StringReader]::new($xmlString)
        $XmlReader = [System.Xml.XmlTextReader]::new($StringReader)
        $Deserializer = $ctor.Invoke($XmlReader)
        $null = $Type.GetMethod('Done', [System.Reflection.BindingFlags]'nonpublic,instance')
        while (!$Type.InvokeMember("Done", "InvokeMethod,NonPublic,Instance", $null, $Deserializer, @())) {
            try {
                $Type.InvokeMember("Deserialize", "InvokeMethod,NonPublic,Instance", $null, $Deserializer, @())
            }
            catch {
                Write-Warning "Could not deserialize ${string}: $_"
            }
        }
        $XmlReader.Close()
        $StringReader.Dispose()
    }
}
#EndRegion '.\Private\ConvertFrom-CLIXml.ps1' 34
#Region '.\Private\ConvertTo-CCMCodeStringFromObject.ps1' 0
function ConvertTo-CCMCodeStringFromObject {
    # TODO - Add help
    [CmdletBinding()]
    [OutputType([string])]
    param
    (
        [Parameter(Mandatory = $true,
            Position = 0)]
        [ValidateNotNullOrEmpty()]
        [Alias('object', 'data', 'input')]
        [psobject]$inputObject
    )
    $tempString = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes([Management.Automation.PsSerializer]::Serialize($inputObject)))
    $MemoryStream = [System.IO.MemoryStream]::new()
    $CompressionStream = [System.IO.Compression.GZipStream]::new($MemoryStream, [System.IO.Compression.CompressionMode]::Compress)
    $StreamWriter = [System.IO.StreamWriter]::new($CompressionStream)
    $StreamWriter.Write($tempString)
    $StreamWriter.Close()
    $CompressedData = [System.Convert]::ToBase64String($MemoryStream.ToArray())
    return $CompressedData
}
#EndRegion '.\Private\ConvertTo-CCMCodeStringFromObject.ps1' 22
#Region '.\Private\Get-CCMConnection.ps1' 0
function Get-CCMConnection {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$Prefer = 'CimSession',
        [Parameter(Mandatory = $false)]
        [Microsoft.Management.Infrastructure.CimSession]$CimSession,
        [Parameter(Mandatory = $false)]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string]$ComputerName = $env:ComputerName
    )

    $return = @{
        connectionSplat = @{ }
    }

    switch ($PSBoundParameters.Keys) {
        'CimSession' {
            Write-Verbose "CimSession passed to Get-CCMConnection - Passing CimSession out"
            $return['connectionSplat'] = @{ CimSession = $CimSession }
            $return['ComputerName'] = $CimSession.ComputerName
            $return['ConnectionType'] = 'CimSession'
        }
        'PSSession' {
            Write-Verbose "Session passed to Get-CCMConnection - Passing Session out"
            $return['connectionSplat'] = @{ Session = $PSSession }
            $return['ComputerName'] = $PSSession.ComputerName
            $return['ConnectionType'] = 'PSSession'
        }
        'ComputerName' {
            $return['ComputerName'] = $ComputerName
            switch ($ComputerName -eq $env:ComputerName) {
                $true {
                    Write-Verbose "Local computer provided - will return empty connection"
                    $return['connectionSplat'] = @{ }
                    $return['ConnectionType'] = 'ComputerName'
                }
                $false {
                    switch ($Prefer) {
                        'CimSession' {
                            if ($ExistingCimSession = Get-CimSession -ComputerName $ComputerName -ErrorAction Ignore) {
                                Write-Verbose "Active CimSession found for $ComputerName - Passing CimSession out"
                                $return['connectionSplat'] = @{ CimSession = $ExistingCimSession[0] }
                                $return['ConnectionType'] = 'CimSession'
                            }
                            elseif ($ExistingSession = (Get-PSSession -ErrorAction Ignore).Where({$_.ComputerName -eq $ComputerName -and $_.State -eq 'Opened'})) {
                                Write-Verbose "Fallback active PSSession found for $ComputerName - Passing Session out"
                                $return['connectionSplat'] = @{ Session = $ExistingSession[0] }
                                $return['ConnectionType'] = 'PSSession'
                            }
                            else {
                                Write-Verbose "No active CimSession (preferred), or PSSession found for $ComputerName - falling back to -ComputerName"
                                $return['connectionSplat'] = @{ ComputerName = $Connection }
                                $return['ConnectionType'] = 'CimSession'
                            }
                        }
                        'PSSession' {
                            if ($ExistingSession = (Get-PSSession -ErrorAction Ignore).Where({$_.ComputerName -eq $ComputerName -and $_.State -eq 'Opened'})) {
                                Write-Verbose "Active PSSession found for $ComputerName - Passing Session out"
                                $return['connectionSplat'] = @{ Session = $ExistingSession[0] }
                                $return['ConnectionType'] = 'PSSession'
                            }
                            elseif ($ExistingCimSession = Get-CimSession -ComputerName $ComputerName -ErrorAction Ignore) {
                                Write-Verbose "Fallback active CimSession found for $ComputerName - Passing CimSession out"
                                $return['connectionSplat'] = @{ CimSession = $ExistingCimSession[0] }
                                $return['ConnectionType'] = 'CimSession'
                            }
                            else {
                                Write-Verbose "No active PSSession (preferred), or CimSession found for $ComputerName - falling back to -ComputerName"
                                $return['connectionSplat'] = @{ ComputerName = $ComputerName }
                                $return['ConnectionType'] = 'PSSession'
                            }
                        }
                    }
                }
            }
        }
    }

    Write-Output $return
}
#EndRegion '.\Private\Get-CCMConnection.ps1' 86
#Region '.\Private\Get-StringFromTimespan.ps1' 0
function Get-StringFromTimespan {
    param(
        [parameter(Mandatory = $false, ParameterSetName = 'ByTimeInterval')]
        [int]$Days,
        [parameter(Mandatory = $false, ParameterSetName = 'ByTimeInterval')]
        [int]$Hours,
        [parameter(Mandatory = $false, ParameterSetName = 'ByTimeInterval')]
        [int]$Minutes,
        [parameter(Mandatory = $false, ParameterSetName = 'ByTimeInterval')]
        [int]$Seconds,
        [parameter(Mandatory = $false, ParameterSetName = 'ByTimeInterval')]
        [int]$Milliseconds,
        [parameter(Mandatory = $true, ParameterSetName = 'ByTimeSpan')]
        [timespan]$TimeSpan
    )

    $TS = switch ($PSCmdlet.ParameterSetName) {
        'ByTimeInterval' {
            New-TimeSpan @PSBoundParameters
        }
        'ByTimeSpan' {
            Write-Output $TimeSpan
        }
    }

    $DescriptiveTSArray = switch ('Days', 'Hours', 'Minutes', 'Seconds', 'Milliseconds') {
        default {
            $TimeIncrement = $PSItem
            switch ($TS.$TimeIncrement) {
                0 {
                    continue
                }
                1 {
                    [string]::Format('{0} {1}', $PSItem, ($TimeIncrement -replace 's$'))
                }
                default {
                    [string]::Format('{0} {1}', $PSItem, $TimeIncrement)
                }
            }
        }
    }

    switch ($DescriptiveTSArray.Count) {
        0 {
            $PSItem
        }
        default {
            [string]::Join(' ', $DescriptiveTSArray)
        }
    }
}
#EndRegion '.\Private\Get-StringFromTimespan.ps1' 52
#Region '.\Public\ConvertFrom-CCMLogFile.ps1' 0
Function ConvertFrom-CCMLogFile {
    [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')]
    [OutputType([CMLogEntry[]])]
    [Alias('Get-CCMLogFile')]
    param (
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName)]
        [Alias('Fullname', 'LogFilePath')]
        [string[]]$Path,
        [Parameter(Mandatory = $false, ParameterSetName = 'ParseSMSTS')]
        [switch]$ParseSMSTS,
        [Parameter(Mandatory = $false, ParameterSetName = 'CustomFilter')]
        [string]$Filter,
        [Parameter(Mandatory = $false)]
        [ValidateSet('None', 'Informational', 'Warning', 'Error')]
        [Alias('Type')]
        [string[]]$Severity = @('None', 'Informational', 'Warning', 'Error'),
        [Parameter(Mandatory = $false)]
        [datetime]$TimestampGreaterThan = [datetime]::MinValue,
        [Parameter(Mandatory = $false)]
        [datetime]$TimestampLessThan = [datetime]::MaxValue
    )
    begin {
        #region If either timestamp filter parameter is specified we will validate the timestamp
        $CheckTimestampFilter = $PSBoundParameters.ContainsKey('TimestampGreaterThan') -or $PSBoundParameters.ContainsKey('TimestampLessThan')
        #endregion If either timestamp filter parameter is specified we will validate the timestamp
    }
    process {
        foreach ($LogFile in $Path) {
            #region ingest log file with StreamReader. Quick, and prevents locks
            $File = [System.IO.File]::Open($LogFile, 'Open', 'Read', 'ReadWrite')
            $StreamReader = New-Object System.IO.StreamReader($File)
            [string]$LogFileRaw = $StreamReader.ReadToEnd()
            $StreamReader.Close()
            $StreamReader.Dispose()
            $File.Close()
            $File.Dispose()
            #endregion ingest log file with StreamReader. Quick, and prevents locks

            #region perform a regex match to determine the 'type' of log we are working with and parse appropriately
            switch -regex ($LogFileRaw) {
                #region parse a 'typical' MEMCM log
                'LOG\[(.*?)\]LOG(.*?)time(.*?)date' {
                    # split on what we know is a line beginning
                    switch -regex ([regex]::Split($LogFileRaw, '<!\[LOG\[')) {
                        #region ignore empty lines in file
                        '^\s*$' {
                            # ignore empty lines
                            continue
                        }
                        #endregion ignore empty lines in file

                        #region process non-empty lines from file
                        default {
                            $UnparsedLogLine = $PSItem
                            $Parse = $false
                            $Parse = switch ($PSCmdlet.ParameterSetName) {
                                #region if ParseSMSTS specified, check logline for known string for SMS step success / failure
                                ParseSMSTS {
                                    switch -regex ($UnparsedLogLine) {
                                        'win32 code 0|failed to run the action' {
                                            $true
                                        }
                                    }
                                }
                                #endregion if ParseSMSTS specified, check logline for known string for SMS step success / failure

                                #region if CustomerFilter is specified, check logline against the string as a regex match
                                CustomFilter {
                                    switch -regex ($UnparsedLogLine) {
                                        $Filter {
                                            $true
                                        }
                                    }
                                }
                                #endregion if CustomerFilter is specified, check logline against the string as a regex match

                                #region if no filtering is provided then the we parse all loglines
                                default {
                                    $true
                                }
                                #endregion if no filtering is provided then the we parse all loglines
                            }

                            switch ($Parse) {
                                $true {
                                    <#
                                        split Log line into an array on what we know is the end of the message section
                                        first item contains the message which can be parsed
                                        second item contains all the information about the message/line (ie. type, component, datetime, thread) which can be parsed
                                    #>

                                    $LogLineArray = [regex]::Split($UnparsedLogLine, ']LOG]!><')

                                    # Strip the log message out of our first array index
                                    $Message = $LogLineArray[0]

                                    # Split LogLineArray into a a sub array based on double quotes to pull log line information
                                    $LogLineSubArray = $LogLineArray[1].Split([char]34)

                                    $LogLine = [CMLogEntry]::New($Message
                                        , ($Type = [Severity]$LogLineSubArray[9])
                                        , $LogLineSubArray[5]
                                        , $LogLineSubArray[11])

                                    #region parse log based on severity, which defaults to any severity if the parameter is not specified
                                    switch ($Severity) {
                                        ($Type) {
                                            $LogLine.ResolveTimestamp($LogLineSubArray, [CMLogType]::FullCMTrace)
                                            switch ($CheckTimestampFilter) {
                                                $true {
                                                    switch ($LogLine.TestTimestampFilter($TimestampGreaterThan, $TimestampLessThan)) {
                                                        $true {
                                                            $LogLine
                                                        }
                                                    }
                                                }
                                                $false {
                                                    $LogLine
                                                }
                                            }
                                        }
                                    }
                                    #endregion parse log based on severity, which defaults to any severity if the parameter is not specified
                                }
                            }
                        }
                        #endregion process non-empty lines from file
                    }
                }
                #endregion parse a 'typical' MEMCM log

                #region parse a 'simple' MEMCM log, usually found on site systems
                '\$\$\<(.*?)\>\<thread=' {
                    switch -regex ($LogFileRaw -split [System.Environment]::NewLine) {
                        #region ignore empty lines in file
                        '^\s*$' {
                            # ignore empty lines
                            continue
                        }
                        #endregion ignore empty lines in file

                        #region process non-empty lines from file
                        default {
                            $UnparsedLogLine = $PSItem
                            $Parse = $false
                            $Parse = switch ($PSCmdlet.ParameterSetName) {
                                #region if CustomerFilter is specified, check logline against the string as a regex match
                                CustomFilter {
                                    switch -regex ($UnparsedLogLine) {
                                        $Filter {
                                            $true
                                        }
                                    }
                                }
                                #endregion if CustomerFilter is specified, check logline against the string as a regex match

                                #region if no filtering is provided then the we parse all loglines
                                default {
                                    $true
                                }
                                #endregion if no filtering is provided then the we parse all loglines
                            }
                            switch ($Parse) {
                                $true {
                                    <#
                                        split Log line into an array
                                        first item contains the message which can be parsed
                                        second item contains all the information about the message/line (ie. type, component, timestamp, thread) which can be parsed
                                    #>

                                    $LogLineArray = [regex]::Split($UnparsedLogLine, '\$\$<')

                                    # Strip the log message out of our first array index
                                    $Message = $LogLineArray[0]

                                    # Split LogLineArray into a a sub array based on double quotes to pull log line information
                                    $LogLineSubArray = $LogLineArray[1].Split('><', [System.StringSplitOptions]::RemoveEmptyEntries)

                                    switch -regex ($Message) {
                                        #region ignore empty message lines
                                        '^\s*$' {
                                            # ignore empty messages
                                            continue
                                        }
                                        #endregion ignore empty message lines

                                        #region process non-empty message lines
                                        default {
                                            $LogLine = [CMLogEntry]::New($Message
                                                , [Severity]0
                                                , $LogLineSubArray[0].Trim()
                                                , ($LogLineSubArray[2].Split([char]32, [System.StringSplitOptions]::RemoveEmptyEntries))[0].Substring(7))

                                            $LogLine.ResolveTimestamp($LogLineSubArray, [CMLogType]::SimpleCMTrace)
                                            switch ($CheckTimestampFilter) {
                                                $true {
                                                    switch ($LogLine.TestTimestampFilter($TimestampGreaterThan, $TimestampLessThan)) {
                                                        $true {
                                                            $LogLine
                                                        }
                                                    }
                                                }
                                                $false {
                                                    $LogLine
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        #endregion process non-empty lines from file
                    }
                }
                #endregion parse a 'simple' MEMCM log, usually found on site systems
            }
            #endregion perform a regex match to determine the 'type' of log we are working with and parse appropriately
        }
    }
}
#EndRegion '.\Public\ConvertFrom-CCMLogFile.ps1' 219
#Region '.\Public\ConvertFrom-CCMSchedule.ps1' 0
Function ConvertFrom-CCMSchedule {
    Param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('Schedules')]
        [string[]]$ScheduleString
    )
    begin {
        #region TypeMap for returning readable window type
        $TypeMap = @{
            1 = 'SMS_ST_NonRecurring'
            2 = 'SMS_ST_RecurInterval'
            3 = 'SMS_ST_RecurWeekly'
            4 = 'SMS_ST_RecurMonthlyByWeekday'
            5 = 'SMS_ST_RecurMonthlyByDate'
        }
        #endregion TypeMap for returning readable window type

        #region function to return a formatted day such as 1st, 2nd, or 3rd
        function Get-FancyDay {
            <#
                .SYNOPSIS
                Convert the input 'Day' integer to a 'fancy' value such as 1st, 2nd, 4d, 4th, etc.
            #>

            param(
                [int]$Day
            )
            $Suffix = switch -regex ($Day) {
                '1(1|2|3)$' {
                    'th'
                    break
                }
                '.?1$' {
                    'st'
                    break
                }
                '.?2$' {
                    'nd'
                    break
                }
                '.?3$' {
                    'rd'
                    break
                }
                default {
                    'th'
                    break
                }
            }
            [string]::Format('{0}{1}', $Day, $Suffix)
        }
        #endregion function to return a formatted day such as 1st, 2nd, or 3rd
    }
    process {
        # we will split the schedulestring input into 16 characters, as some are stored as multiple in one
        foreach ($Schedule in ($ScheduleString -split '(\w{16})' | Where-Object { $_ })) {
            $MW = [ordered]@{ }

            # the first 8 characters are the Start of the MW, while the last 8 characters are the recurrence schedule
            $Start = $Schedule.Substring(0, 8)
            $Recurrence = $Schedule.Substring(8, 8)

            # Convert to binary string and pad left with 0 to ensure 32 character length for consistent parsing
            $binaryRecurrence = [Convert]::ToString([int64]"0x$Recurrence".ToString(), 2).PadLeft(32, 48)

            [bool]$IsGMT = [Convert]::ToInt32($binaryRecurrence.Substring(31, 1), 2)

            switch ($Start) {
                '00012000' {
                    # this is as 'simple' schedule, such as a CI that 'runs once a day' or 'every 8 hours'
                }
                default {
                    # Convert to binary string and pad left with 0 to ensure 32 character length for consistent parsing
                    $binaryStart = [Convert]::ToString([int64]"0x$Start".ToString(), 2).PadLeft(32, 48)

                    # Collect timedata and ensure we pad left with 0 to ensure 2 character length
                    [string]$StartMinute = ([Convert]::ToInt32($binaryStart.Substring(0, 6), 2).ToString()).PadLeft(2, 48)
                    [string]$MinuteDuration = [Convert]::ToInt32($binaryStart.Substring(26, 6), 2).ToString()
                    [string]$StartHour = ([Convert]::ToInt32($binaryStart.Substring(6, 5), 2).ToString()).PadLeft(2, 48)
                    [string]$StartDay = ([Convert]::ToInt32($binaryStart.Substring(11, 5), 2).ToString()).PadLeft(2, 48)
                    [string]$StartMonth = ([Convert]::ToInt32($binaryStart.Substring(16, 4), 2).ToString()).PadLeft(2, 48)
                    [String]$StartYear = [Convert]::ToInt32($binaryStart.Substring(20, 6), 2) + 1970

                    # set our StartDateTimeObject variable by formatting all our calculated datetime components and piping to Get-Date
                    $Kind = switch ($IsGMT) {
                        $true {
                            [DateTimeKind]::Utc
                        }
                        $false {
                            [DateTimeKind]::Local
                        }
                    }
                    $StartDateTimeObject = [datetime]::new($StartYear, $StartMonth, $StartDay, $StartHour, $StartMinute, '00', $Kind)
                }
            }

            <#
                Day duration is found by calculating how many times 24 goes into our TotalHourDuration (number of times being DayDuration)
                and getting the remainder for HourDuration by using % for modulus
            #>

            $TotalHourDuration = [Convert]::ToInt32($binaryRecurrence.Substring(0, 5), 2)

            switch ($TotalHourDuration -gt 24) {
                $true {
                    $Hours = $TotalHourDuration % 24
                    $DayDuration = ($TotalHourDuration - $Hours) / 24
                    $HourDuration = $Hours
                }
                $false {
                    $HourDuration = $TotalHourDuration
                    $DayDuration = 0
                }
            }

            $RecurType = [Convert]::ToInt32($binaryRecurrence.Substring(10, 3), 2)

            $MW['SmsProviderObjectPath'] = $TypeMap[$RecurType]
            $MW['DayDuration'] = $DayDuration
            $MW['HourDuration'] = $HourDuration
            $MW['MinuteDuration'] = $MinuteDuration
            $MW['IsGMT'] = $IsGMT
            $MW['StartTime'] = $StartDateTimeObject

            Switch ($RecurType) {
                1 {
                    $MW['Description'] = [string]::Format('Occurs on {0}', $StartDateTimeObject)
                }
                2 {
                    $MinuteSpan = [Convert]::ToInt32($binaryRecurrence.Substring(13, 6), 2)
                    $Hourspan = [Convert]::ToInt32($binaryRecurrence.Substring(19, 5), 2)
                    $DaySpan = [Convert]::ToInt32($binaryRecurrence.Substring(24, 5), 2)
                    if ($MinuteSpan -ne 0) {
                        $Span = 'minutes'
                        $Interval = $MinuteSpan
                    }
                    elseif ($HourSpan -ne 0) {
                        $Span = 'hours'
                        $Interval = $HourSpan
                    }
                    elseif ($DaySpan -ne 0) {
                        $Span = 'days'
                        $Interval = $DaySpan
                    }

                    $MW['Description'] = [string]::Format('Occurs every {0} {1} effective {2}', $Interval, $Span, $StartDateTimeObject)
                    $MW['MinuteSpan'] = $MinuteSpan
                    $MW['HourSpan'] = $Hourspan
                    $MW['DaySpan'] = $DaySpan
                }
                3 {
                    $Day = [Convert]::ToInt32($binaryRecurrence.Substring(13, 3), 2)
                    $WeekRecurrence = [Convert]::ToInt32($binaryRecurrence.Substring(16, 3), 2)
                    $MW['Description'] = [string]::Format('Occurs every {0} weeks on {1} effective {2}', $WeekRecurrence, $([DayOfWeek]($Day - 1)), $StartDateTimeObject)
                    $MW['Day'] = $Day
                    $MW['ForNumberOfWeeks'] = $WeekRecurrence
                }
                4 {
                    $Day = [Convert]::ToInt32($binaryRecurrence.Substring(13, 3), 2)
                    $ForNumberOfMonths = [Convert]::ToInt32($binaryRecurrence.Substring(16, 4), 2)
                    $WeekOrder = [Convert]::ToInt32($binaryRecurrence.Substring(20, 3), 2)
                    $WeekRecurrence = switch ($WeekOrder) {
                        0 {
                            'Last'
                        }
                        default {
                            $(Get-FancyDay -Day $WeekOrder)
                        }
                    }
                    $MW['Description'] = [string]::Format('Occurs the {0} {1} of every {2} months effective {3}', $WeekRecurrence, $([DayOfWeek]($Day - 1)), $ForNumberOfMonths, $StartDateTimeObject)
                    $MW['Day'] = $Day
                    $MW['ForNumberOfMonths'] = $ForNumberOfMonths
                    $MW['WeekOrder'] = $WeekOrder
                }
                5 {
                    $MonthDay = [Convert]::ToInt32($binaryRecurrence.Substring(13, 5), 2)
                    $MonthRecurrence = switch ($MonthDay) {
                        0 {
                            # $Today = [datetime]::Today
                            # [datetime]::DaysInMonth($Today.Year, $Today.Month)
                            'the last day'
                        }
                        default {
                            "day $PSItem"
                        }
                    }
                    $ForNumberOfMonths = [Convert]::ToInt32($binaryRecurrence.Substring(18, 4), 2)
                    $MW['Description'] = [string]::Format('Occurs {0} of every {1} months effective {2}', $MonthRecurrence, $ForNumberOfMonths, $StartDateTimeObject)
                    $MW['ForNumberOfMonths'] = $ForNumberOfMonths
                    $MW['MonthDay'] = $MonthDay
                }
                Default {
                    Write-Error "Parsing Schedule String resulted in invalid type of $RecurType"
                }
            }

            [pscustomobject]$MW
        }
    }
}
#EndRegion '.\Public\ConvertFrom-CCMSchedule.ps1' 199
#Region '.\Public\ConvertTo-CCMLogFile.ps1' 0
function ConvertTo-CCMLogFile {
    param(
        [CMLogEntry[]]$CMLogEntries,
        [string]$LogPath
    )
    $LogContent = foreach ($Entry in ($CMLogEntries | Sort-Object -Property Timestamp)) {
        $Entry.ConvertToCMLogLine()
    }

    Set-Content -Path $LogPath -Value $LogContent -Force
}
#EndRegion '.\Public\ConvertTo-CCMLogFile.ps1' 12
#Region '.\Public\Get-CCMApplication.ps1' 0
function Get-CCMApplication {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false)]
        [string[]]$ApplicationName,
        [Parameter(Mandatory = $false)]
        [string[]]$ApplicationID,
        [Parameter(Mandatory = $false)]
        [switch]$IncludeIcon,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    # ENHANCE - Support lazy loading properties
    begin {
        #region define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
        $getapplicationsplat = @{
            NameSpace = 'root\CCM\ClientSDK'
            ClassName = 'CCM_Application'
        }
        #endregion define our hash tables for parameters to pass to Get-CIMInstance and our return hash table

        #region EvaluationState hashtable for mapping
        $evaluationStateMap = @{
            0  = 'No state information is available.'
            1  = 'Application is enforced to desired/resolved state.'
            2  = 'Application is not required on the client.'
            3  = 'Application is available for enforcement (install or uninstall based on resolved state). Content may/may not have been downloaded.'
            4  = 'Application last failed to enforce (install/uninstall).'
            5  = 'Application is currently waiting for content download to complete.'
            6  = 'Application is currently waiting for content download to complete.'
            7  = 'Application is currently waiting for its dependencies to download.'
            8  = 'Application is currently waiting for a service (maintenance) window.'
            9  = 'Application is currently waiting for a previously pending reboot.'
            10 =    'Application is currently waiting for serialized enforcement.'
            11 =    'Application is currently enforcing dependencies.'
            12 =    'Application is currently enforcing.'
            13 =    'Application install/uninstall enforced and soft reboot is pending.'
            14 =    'Application installed/uninstalled and hard reboot is pending.'
            15 =    'Update is available but pending installation.'
            16 =    'Application failed to evaluate.'
            17 =    'Application is currently waiting for an active user session to enforce.'
            18 =    'Application is currently waiting for all users to logoff.'
            19 =    'Application is currently waiting for a user logon.'
            20 =    'Application in progress, waiting for retry.'
            21 =    'Application is waiting for presentation mode to be switched off.'
            22 =    'Application is pre-downloading content (downloading outside of install job).'
            23 =    'Application is pre-downloading dependent content (downloading outside of install job).'
            24 =    'Application download failed (downloading during install job).'
            25 =    'Application pre-downloading failed (downloading outside of install job).'
            26 =    'Download success (downloading during install job).'
            27 =    'Post-enforce evaluation.'
            28 =    'Waiting for network connectivity.'
        }
        #endregion EvaluationState hashtable for mapping
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Return = [ordered]@{ }
            $Return['ComputerName'] = $Computer

            try {
                $FilterParts = switch ($PSBoundParameters.Keys) {
                    'ApplicationName' {
                        [string]::Format('$AppFound.Name -eq "{0}"', [string]::Join('" -or $AppFound.Name -eq "', $ApplicationName))
                    }
                    'ApplicationID' {
                        [string]::Format('$AppFound.ID -eq "{0}"', [string]::Join('" -or $AppFound.ID -eq "', $ApplicationID))
                    }
                }
                [ciminstance[]]$applications = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getapplicationsplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getapplicationsplat @connectionSplat
                    }
                }
                if ($applications -is [Object] -and $applications.Count -gt 0) {
                    #region Filterering is not possible on the CCM_Application class, so instead we loop and compare properties to filter
                    $Condition = switch ($null -ne $FilterParts) {
                        $true {
                            [scriptblock]::Create([string]::Join(' -or ', $FilterParts))
                        }
                    }
                    foreach ($AppFound in $applications) {
                        $AppToReturn = switch ($null -ne $Condition) {
                            $true {
                                switch ($Condition.Invoke()) {
                                    $true {
                                        $AppFound
                                    }
                                }
                            }
                            $false {
                                $AppFound
                            }
                        }
                        switch ($null -ne $AppToReturn) {
                            $true {
                                $PropsToShow = 'Name', 'FullName', 'SoftwareVersion', 'Publisher', 'Description',
                                'Id', 'Revision', 'EvaluationState', 'ErrorCode', 'AllowedActions', 'ResolvedState',
                                'InstallState', 'ApplicabilityState', 'ConfigureState', 'LastEvalTime', 'LastInstallTime',
                                'StartTime', 'Deadline', 'NextUserScheduledTime', 'IsMachineTarget', 'IsPreflightOnly',
                                'NotifyUser', 'UserUIExperience', 'OverrideServiceWindow', 'RebootOutsideServiceWindow',
                                'AppDTs', 'ContentSize', 'DeploymentReport', 'EnforcePreference', 'EstimatedInstallTime',
                                'FileTypes', 'HighImpactDeployment', 'InformativeUrl', 'InProgressActions', 'PercentComplete',
                                'ReleaseDate', 'SupersessionState', 'Type'
                                foreach ($PropertyName in $PropsToShow) {
                                    $Return[$PropertyName] = $AppToReturn.$PropertyName
                                }

                                switch ($IncludeIcon.IsPresent) {
                                    $true {
                                        $Return['Icon'] = $AppToReturn.Icon
                                    }
                                }
                                [pscustomobject]$Return
                            }
                        }
                    }
                    #endregion Filterering is not possible on the CCM_Application class, so instead we loop and compare properties to filter
                }
                else {
                    Write-Warning "No deployed applications found for $Computer based on input filters"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMApplication.ps1' 155
#Region '.\Public\Get-CCMBaseline.ps1' 0
function Get-CCMBaseline {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    [Alias('Get-CCMCB')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [string[]]$BaselineName = 'NotSpecified',
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region Setup our *-CIM* parameters that will apply to the CIM cmdlets in use based on input parameters
        $getBaselineSplat = @{
            Namespace   = 'root\ccm\dcm'
            ErrorAction = 'Stop'
        }
        #endregion Setup our common *-CIM* parameters that will apply to the CIM cmdlets in use based on input parameters

        #region hash table for translating compliance status
        $LastComplianceStatus = @{
            0 = 'Non-Compliant'
            1 = 'Compliant'
            2 = 'Compliance State Unknown'
            4 = 'Error'
        }
        #endregion hash table for translating compliance status
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Return = [ordered]@{ }
            $Return['ComputerName'] = $Computer

            $BLQuery = switch ($PSBoundParameters.ContainsKey('BaselineName') -and $BaselineName -ne 'NotSpecified') {
                $true {
                    [string]::Format('SELECT * FROM SMS_DesiredConfiguration WHERE DisplayName = "{0}"', [string]::Join('" OR DisplayName = "', $BaselineName))
                }
                $false {
                    "SELECT * FROM SMS_DesiredConfiguration"
                }
            }

            #region Query WMI for Configuration Baselines based off DisplayName
            Write-Verbose "Checking for Configuration Baselines on [ComputerName='$Computer'] with [Query=`"$BLQuery`"]"
            $getBaselineSplat['Query'] = $BLQuery
            try {
                $Baselines = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getBaselineSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getBaselineSplat @connectionSplat
                    }
                }
            }
            catch {
                # need to improve this - should catch access denied vs RPC, and need to do this on ALL CIM related queries across the module.
                # Maybe write a function???
                Write-Error "Failed to query for baselines on $Connection - $($_)"
                continue
            }
            #endregion Query WMI for Configuration Baselines based off DisplayName

            #region Based on results of CIM Query, return additional information around compliance and eval time
            switch ($null -eq $Baselines) {
                $false {
                    foreach ($BL in $Baselines) {
                        $Return['BaselineName'] = $BL.DisplayName
                        $Return['Version'] = $BL.Version
                        $Return['LastComplianceStatus'] = $LastComplianceStatus[[int]$BL.LastComplianceStatus]
                        $Return['LastEvalTime'] = $BL.LastEvalTime
                        [pscustomobject]$Return
                    }
                }
                $true {
                    Write-Warning "Failed to identify any Configuration Baselines on [ConnectionName='$Connection'] with [Query=`"$BLQuery`"]"
                }
            }
            #endregion Based on results of CIM Query, return additional information around compliance and eval time
        }
    }
}
#EndRegion '.\Public\Get-CCMBaseline.ps1' 102
#Region '.\Public\Get-CCMCacheContent.ps1' 0
function Get-CCMCacheContent {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getCacheContentSplat = @{
            Namespace   = 'root\CCM\SoftMgmtAgent'
            ClassName   = 'CacheInfoEx'
            ErrorAction = 'Stop'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$CacheContent = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getCacheContentSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getCacheContentSplat @connectionSplat
                    }
                }
                if ($CacheContent -is [Object] -and $CacheContent.Count -gt 0) {
                    foreach ($Item in $CacheContent) {
                        $Result['ContentId'] = $Item.ContentId
                        $Result['ContentVersion'] = $Item.ContentVer
                        $Result['Location'] = $Item.Location
                        $Result['LastReferenceTime'] = $Item.LastReferenced
                        $Result['ReferenceCount'] = $Item.ReferenceCount
                        $Result['ContentSize'] = $Item.ContentSize
                        $Result['ContentComplete'] = $Item.ContentComplete
                        $Result['CacheElementId'] = $Item.CacheID
                        [pscustomobject]$Result
                    }
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMCacheContent.ps1' 69
#Region '.\Public\Get-CCMCacheInfo.ps1' 0
function Get-CCMCacheInfo {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getCacheInfoSplat = @{
            Namespace   = 'root\CCM\SoftMgmtAgent'
            ClassName   = 'CacheConfig'
            ErrorAction = 'Stop'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$CimResult = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getCacheInfoSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getCacheInfoSplat @connectionSplat
                    }
                }
                if ($CimResult -is [Object] -and $CimResult.Count -gt 0) {
                    foreach ($Object in $CimResult) {
                        $Result['Location'] = $Object.Location
                        $Result['Size'] = $Object.Size
                        [PSCustomObject]$Result
                    }
                }
                else {
                    $Result['Location'] = $null
                    $Result['Size'] = $null
                    [PSCustomObject]$Result
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMCacheInfo.ps1' 68
#Region '.\Public\Get-CCMCimInstance.ps1' 0
function Get-CCMCimInstance {
    [CmdletBinding(DefaultParameterSetName = 'CimQuery-ComputerName')]
    Param(
        [Parameter(Mandatory = $false)]
        [string]$Namespace = 'root\cimv2',
        [Parameter(Mandatory = $true, ParameterSetName = 'CimFilter-CimSession')]
        [Parameter(Mandatory = $true, ParameterSetName = 'CimFilter-PSSession')]
        [Parameter(Mandatory = $true, ParameterSetName = 'CimFilter-ComputerName')]
        [string]$ClassName,
        [Parameter(Mandatory = $false, ParameterSetName = 'CimFilter-CimSession')]
        [Parameter(Mandatory = $false, ParameterSetName = 'CimFilter-PSSession')]
        [Parameter(Mandatory = $false, ParameterSetName = 'CimFilter-ComputerName')]
        [string]$Filter,
        [Parameter(Mandatory = $true, ParameterSetName = 'CimQuery-CimSession')]
        [Parameter(Mandatory = $true, ParameterSetName = 'CimQuery-PSSession')]
        [Parameter(Mandatory = $true, ParameterSetName = 'CimQuery-ComputerName')]
        [string]$Query,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimQuery-CimSession')]
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimFilter-CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'PassThrough-ComputerName')]
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimQuery-ComputerName')]
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimFilter-ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'CimQuery-PSSession')]
        [Parameter(Mandatory = $false, ParameterSetName = 'CimFilter-PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'CimQuery-ComputerName')]
        [Parameter(Mandatory = $false, ParameterSetName = 'CimFilter-ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference = 'CimSession'
    )
    begin {
        $ConnectionChecker = ($PSCmdlet.ParameterSetName).Split('-')[1]

        $GetCimInstanceSplat = @{ }
        switch ($PSBoundParameters.Keys) {
            'Namespace' {
                $GetCimInstanceSplat['NameSpace'] = $Namespace
            }
            'ClassName' {
                $GetCimInstanceSplat['ClassName'] = $ClassName
            }
            'Filter' {
                $GetCimInstanceSplat['Filter'] = $Filter
            }
            'Query' {
                $GetCimInstanceSplat['Query'] = $Query
            }
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $ConnectionChecker -ValueOnly -Scope Local)) {
            $getConnectionInfoSplat = @{
                $ConnectionChecker = $Connection
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat -Prefer $ConnectionPreference
            $ConnectionPreference = $ConnectionInfo.ConnectionType
            $connectionSplat = $ConnectionInfo.connectionSplat

            switch ($ConnectionPreference) {
                'CimSession' {
                    Get-CimInstance @GetCimInstanceSplat @connectionSplat
                }
                'PSSession' {
                    $GetCimInstanceOverPSSessionSplat = @{
                        ArgumentList = $GetCimInstanceSplat
                        ScriptBlock  = {
                            param($GetCimInstanceSplat)
                            Get-CimInstance @GetCimInstanceSplat
                        }
                    }

                    Invoke-Command @GetCimInstanceOverPSSessionSplat @connectionSplat
                }
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMCimInstance.ps1' 82
#Region '.\Public\Get-CCMClientDirectory.ps1' 0
function Get-CCMClientDirectory {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getRegistryPropertySplat = @{
            Key      = "SOFTWARE\Microsoft\SMS\Client\Configuration\Client Properties"
            Property = "Local SMS Path"
            RegRoot  = 'HKEY_LOCAL_MACHINE'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            $ReturnHashTable = Get-CCMRegistryProperty @getRegistryPropertySplat @connectionSplat
            foreach ($PC in $ReturnHashTable.GetEnumerator()) {
                $Result['ClientDirectory'] = $ReturnHashTable[$PC.Key].'Local SMS Path'.TrimEnd('\')
            }
            [pscustomobject]$Result
        }
    }
}
#EndRegion '.\Public\Get-CCMClientDirectory.ps1' 48
#Region '.\Public\Get-CCMClientInfo.ps1' 0
function Get-CCMClientInfo {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            # ENHANCE - Decide on an order for the properties

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            #region site code
            $SiteCode = Get-CCMSite @connectionSplat
            $Result['SiteCode'] = $SiteCode.SiteCode
            #endregion site code

            #region Current Management Point
            $Result['CurrentManagementPoint'] = (Get-CCMCurrentManagementPoint @connectionSplat).CurrentManagementPoint
            $Result['CurrentSoftwareUpdatePoint'] = (Get-CCMCurrentSoftwareUpdatePoint @connectionSplat).CurrentSoftwareUpdatePoint
            #endregion Current Management Point

            #region cache info
            $CacheInfo = Get-CCMCacheInfo @connectionSplat
            $Result['CacheLocation'] = $CacheInfo.Location
            $Result['CacheSize'] = $CacheInfo.Size
            #endregion cache info

            #region MEMCM Client Directory
            $Result['ClientDirectory'] = (Get-CCMClientDirectory @connectionSplat).ClientDirectory
            #endregion MEMCM Client Directory
                                    
            #region DNS Suffix
            $Result['DNSSuffix'] = (Get-CCMDNSSuffix @connectionSplat).DNSSuffix
            #endregion DNS Suffix

            #region MEMCM Client GUID
            $GUIDInfo = Get-CCMGUID @connectionSplat
            $Result['GUID'] = $GUIDInfo.GUID
            $Result['ClientGUIDChangeDate'] = $GUIDInfo.ClientGUIDChangeDate
            $Result['PreviousGUID'] = $GUIDInfo.PreviousGUID
            #endregion MEMCM Client GUID

            #region MEMCM Client Version
            $Result['ClientVersion'] = (Get-CCMClientVersion @connectionSplat).ClientVersion
            #endregion MEMCM Client Version

            #region Last Heartbeat Cycle
            $LastHeartbeat = Get-CCMLastHeartbeat @connectionSplat
            $Result['DDR-LastCycleStartedDate'] = $LastHeartbeat.LastCycleStartedDate
            $Result['DDR-LastReportDate'] = $LastHeartbeat.LastReportDate
            $Result['DDR-LastMajorReportVersion'] = $LastHeartbeat.LastMajorReportVersion
            $Result['DDR-LastMinorReportVersion'] = $LastHeartbeat.LastMinorReportVersion
            #endregion Last Heartbeat Cycle

            #region Last Hardware Inventory Cycle
            $LastHardwareInventory = Get-CCMLastHardwareInventory @connectionSplat
            $Result['HINV-LastCycleStartedDate'] = $LastHardwareInventory.LastCycleStartedDate
            $Result['HINV-LastReportDate'] = $LastHardwareInventory.LastReportDate
            $Result['HINV-LastMajorReportVersion'] = $LastHardwareInventory.LastMajorReportVersion
            $Result['HINV-LastMinorReportVersion'] = $LastHardwareInventory.LastMinorReportVersion
            #endregion Last Hardware Inventory Cycle

            #region Last Software Inventory Cycle
            $LastSoftwareInventory = Get-CCMLastSoftwareInventory @connectionSplat
            $Result['SINV-LastCycleStartedDate'] = $LastSoftwareInventory.LastCycleStartedDate
            $Result['SINV-LastReportDate'] = $LastSoftwareInventory.LastReportDate
            $Result['SINV-LastMajorReportVersion'] = $LastSoftwareInventory.LastMajorReportVersion
            $Result['SINV-LastMinorReportVersion'] = $LastSoftwareInventory.LastMinorReportVersion
            #endregion Last Software Inventory Cycle

            #region MEMCM Client Log Configuration
            $LogConfiguration = Get-CCMLoggingConfiguration @connectionSplat
            $Result['LogDirectory'] = $LogConfiguration.LogDirectory
            $Result['LogMaxSize'] = $LogConfiguration.LogMaxSize
            $Result['LogMaxHistory'] = $LogConfiguration.LogMaxHistory
            $Result['LogLevel'] = $LogConfiguration.LogLevel
            $Result['LogEnabled'] = $LogConfiguration.LogEnabled
            #endregion MEMCM Client Log Configuration

            #region MEMCM Client internet configuration
            $Result['IsClientOnInternet'] = (Test-CCMIsClientOnInternet @connectionSplat).IsClientOnInternet[0]
            $Result['IsClientAlwaysOnInternet'] = (Test-CCMIsClientAlwaysOnInternet @connectionSplat).IsClientAlwaysOnInternet[0]
            #endregion MEMCM Client internet configuration

            [pscustomobject]$Result
        }
    }
}
#EndRegion '.\Public\Get-CCMClientInfo.ps1' 115
#Region '.\Public\Get-CCMClientVersion.ps1' 0
function Get-CCMClientVersion {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getClientVersionSplat = @{
            Namespace = 'root\CCM'
            Query     = 'SELECT ClientVersion FROM SMS_Client'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$Currentversion = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getClientVersionSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getClientVersionSplat @connectionSplat
                    }
                }
                if ($Currentversion -is [Object] -and $Currentversion.Count -gt 0) {
                    foreach ($SMSClient in $Currentversion) {
                        $Result['ClientVersion'] = $SMSClient.ClientVersion
                        [PSCustomObject]$Result
                    }
                }
                else {
                    Write-Warning "No client version found for $Computer"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMClientVersion.ps1' 64
#Region '.\Public\Get-CCMCurrentManagementPoint.ps1' 0
function Get-CCMCurrentManagementPoint {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    [Alias('Get-CCMCurrentMP', 'Get-CCMMP')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getCurrentMPSplat = @{
            Namespace = 'root\CCM'
            Query     = 'SELECT CurrentManagementPoint FROM SMS_Authority'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$CurrentMP = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getCurrentMPSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getCurrentMPSplat @connectionSplat
                    }
                }
                if ($CurrentMP -is [Object] -and $CurrentMP.Count -gt 0) {
                    foreach ($MP in $CurrentMP) {
                        $Result['CurrentManagementPoint'] = $MP.CurrentManagementPoint
                        [PSCustomObject]$Result
                    }
                }
                else {
                    Write-Warning "No Management Point infomration found for $Computer"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMCurrentManagementPoint.ps1' 65
#Region '.\Public\Get-CCMCurrentSoftwareUpdatePoint.ps1' 0
function Get-CCMCurrentSoftwareUpdatePoint {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    [Alias('Get-CCMCurrentSUP', 'Get-CCMSUP')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $CurrentSUPSplat = @{
            Namespace = 'root\ccm\SoftwareUpdates\WUAHandler'
            Query     = 'SELECT ContentLocation FROM CCM_UpdateSource'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$CurrentSUP = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @CurrentSUPSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @CurrentSUPSplat @connectionSplat
                    }
                }
                if ($CurrentSUP -is [Object] -and $CurrentSUP.Count -gt 0) {
                    foreach ($SUP in $CurrentSUP) {
                        $Result['CurrentSoftwareUpdatePoint'] = $SUP.ContentLocation
                        [PSCustomObject]$Result
                    }
                }
                else {
                    Write-Warning "No Software Update Point information found for $Computer"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMCurrentSoftwareUpdatePoint.ps1' 65
#Region '.\Public\Get-CCMCurrentWindowAvailableTime.ps1' 0
function Get-CCMCurrentWindowAvailableTime {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [parameter(Mandatory = $false)]
        [ValidateSet('All Deployment Service Window',
            'Program Service Window',
            'Reboot Required Service Window',
            'Software Update Service Window',
            'Task Sequences Service Window',
            'Corresponds to non-working hours')]
        [string[]]$MWType = 'Software Update Service Window',
        [Parameter(Mandatory = $false)]
        [bool]$FallbackToAllProgramsWindow,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region Create hashtable for mapping MW types
        $MW_Type = @{
            'All Deployment Service Window'    = 1
            'Program Service Window'           = 2
            'Reboot Required Service Window'   = 3
            'Software Update Service Window'   = 4
            'Task Sequences Service Window'    = 5
            'Corresponds to non-working hours' = 6
        }
        #endregion Create hashtable for mapping MW types

        $getCurrentWindowTimeLeft = @{
            Namespace  = 'root\CCM\ClientSDK'
            ClassName  = 'CCM_ServiceWindowManager'
            MethodName = 'GetCurrentWindowAvailableTime'
            Arguments  = @{ }
        }
        $getUpdateMWExistenceSplat = @{
            Namespace = 'root\CCM\ClientSDK'
            Query     = 'SELECT Duration FROM CCM_ServiceWindow WHERE Type = 4'
        }
        $getSoftwareUpdateFallbackSettingsSplat = @{
            Namespace = 'root\CCM\Policy\Machine\ActualConfig'
            Query     = 'SELECT ServiceWindowManagement FROM CCM_SoftwareUpdatesClientConfig'
        }
        $invokeCommandSplat = @{
            FunctionsToLoad = 'Get-CCMCurrentWindowAvailableTime', 'Get-CCMConnection'
        }

        $StringArgs = @(switch ($PSBoundParameters.Keys) {
                'FallbackToAllProgramsWindow' {
                    [string]::Format('-FallbackToAllProgramsWindow ${0}', $FallbackToAllProgramsWindow)
                }
            })
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                switch ($Computer -eq $env:ComputerName) {
                    $true {
                        $HasUpdateMW = $null -ne (Get-CimInstance @getUpdateMWExistenceSplat @connectionSplat).Duration
                        $FallbackSetting = (Get-CimInstance @getSoftwareUpdateFallbackSettingsSplat @connectionSplat).ServiceWindowManagement

                        foreach ($MW in $MWType) {
                            $MWFallback = switch ($FallbackToAllProgramsWindow) {
                                $true {
                                    switch ($MWType) {
                                        'Software Update Service Window' {
                                            switch ($FallbackSetting -ne $FallbackToAllProgramsWindow) {
                                                $true {
                                                    Write-Warning 'Requested fallback setting does not match the computers fallback setting for software updates'
                                                }
                                            }
                                            switch ($HasUpdateMW) {
                                                $true {
                                                    $FallbackSetting -and $HasUpdateMW
                                                }
                                                $false {
                                                    $true
                                                }
                                            }
                                        }
                                        default {
                                            $FallbackToAllProgramsWindow
                                        }
                                    }
                                }
                                $false {
                                    switch ($MWType) {
                                        'Software Update Service Window' {
                                            switch ($HasUpdateMW) {
                                                $true {
                                                    $FallbackSetting -and $HasUpdateMW
                                                }
                                                $false {
                                                    $true
                                                }
                                            }
                                        }
                                        default {
                                            $false
                                        }
                                    }
                                }
                            }
                            $getCurrentWindowTimeLeft['Arguments']['FallbackToAllProgramsWindow'] = [bool]$MWFallback
                            $getCurrentWindowTimeLeft['Arguments']['ServiceWindowType'] = [uint32]$MW_Type[$MW]
                            $TimeLeft = Invoke-CimMethod @getCurrentWindowTimeLeft @connectionSplat
                            $TimeLeftTimeSpan = New-TimeSpan -Seconds $TimeLeft.WindowAvailableTime
                            $Result['MaintenanceWindowType'] = $MW
                            $Result['FallbackToAllProgramsWindow'] = $MWFallback
                            $Result['WindowAvailableTime'] = [string]::Format('{0} day(s) {1} hour(s) {2} minute(s) {3} second(s)', $TimeLeftTimeSpan.Days, $TimeLeftTimeSpan.Hours, $TimeLeftTimeSpan.Minutes, $TimeLeftTimeSpan.Seconds)
                            [pscustomobject]$Result
                        }
                    }
                    $false {
                        $ScriptBlock = [string]::Format('Get-CCMCurrentWindowAvailableTime {0} {1}', [string]::Join(' ', $StringArgs), [string]::Format("-MWType '{0}'", [string]::Join("', '", $MWType)))
                        $invokeCommandSplat['ScriptBlock'] = [scriptblock]::Create($ScriptBlock)
                        Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                    }
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMCurrentWindowAvailableTime.ps1' 150
#Region '.\Public\Get-CCMDNSSuffix.ps1' 0
function Get-CCMDNSSuffix {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param(
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $GetDNSSuffixScriptBlock = {
            $Client = New-Object -ComObject Microsoft.SMS.Client
            $Client.GetDNSSuffix()
        }
        $invokeCommandSplat = @{
            ScriptBlock = $GetDNSSuffixScriptBlock
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            $Result['DNSSuffix'] = switch ($Computer -eq $env:ComputerName) {
                $true {
                    $GetDNSSuffixScriptBlock.Invoke()
                }
                $false {
                    Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                }
            }
            [pscustomobject]$Result
        }
    }
}
#EndRegion '.\Public\Get-CCMDNSSuffix.ps1' 53
#Region '.\Public\Get-CCMExecStartupTime.ps1' 0
function Get-CCMExecStartupTime {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getCCMExecServiceSplat = @{
            Query = "SELECT State, ProcessID from Win32_Service WHERE Name = 'CCMExec'"
        }
        $getCCMExecProcessSplat = @{ }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$CCMExecService = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getCCMExecServiceSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getCCMExecServiceSplat @connectionSplat
                    }
                }
                if ($CCMExecService -is [Object] -and $CCMExecService.Count -gt 0) {
                    foreach ($Service in $CCMExecService) {
                        $getCCMExecProcessSplat['Query'] = [string]::Format("Select CreationDate from Win32_Process WHERE ProcessID = '{0}'", $Service.ProcessID)
                        [ciminstance[]]$CCMExecProcess = switch ($Computer -eq $env:ComputerName) {
                            $true {
                                Get-CimInstance @getCCMExecProcessSplat @connectionSplat
                            }
                            $false {
                                Get-CCMCimInstance @getCCMExecProcessSplat @connectionSplat
                            }
                        }
                        if ($CCMExecProcess -is [Object] -and $CCMExecProcess.Count -gt 0) {
                            foreach ($Process in $CCMExecProcess) {
                                $Result['ServiceState'] = $Service.State
                                $Result['StartupTime'] = $Process.CreationDate
                                [pscustomobject]$Result
                            }
                        }
                    }
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMExecStartupTime.ps1' 75
#Region '.\Public\Get-CCMGUID.ps1' 0
function Get-CCMGUID {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getGUIDSplat = @{
            Namespace = 'root\CCM'
            Query     = 'SELECT ClientID, ClientIDChangeDate, PreviousClientID FROM CCM_Client'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$CurrentGUID = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getGUIDSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getGUIDSplat @connectionSplat
                    }
                }
                if ($CurrentGUID -is [Object] -and $CurrentGUID.Count -gt 0) {
                    foreach ($GUID in $CurrentGUID) {
                        $Result['GUID'] = $GUID.ClientID
                        $Result['ClientGUIDChangeDate'] = $GUID.ClientIDChangeDate
                        $Result['PreviousGUID'] = $GUID.PreviousClientID
                        [PSCustomObject]$Result
                    }
                }
                else {
                    Write-Warning "No ClientID information found for $Computer"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMGUID.ps1' 67
#Region '.\Public\Get-CCMLastHardwareInventory.ps1' 0
function Get-CCMLastHardwareInventory {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    [Alias('Get-CCMLastHINV')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getLastHinvSplat = @{
            Namespace = 'root\CCM\InvAgt'
            Query     = "SELECT LastCycleStartedDate, LastReportDate, LastMajorReportVersion, LastMinorReportVersion, InventoryActionID FROM InventoryActionStatus WHERE InventoryActionID = '{00000000-0000-0000-0000-000000000001}'"
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$LastHinv = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getLastHinvSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getLastHinvSplat @connectionSplat
                    }
                }
                if ($LastHinv -is [Object] -and $LastHinv.Count -gt 0) {
                    foreach ($Occurrence in $LastHinv) {
                        $Result['LastCycleStartedDate'] = $Occurrence.LastCycleStartedDate
                        $Result['LastReportDate'] = $Occurrence.LastReportDate
                        $Result['LastMajorReportVersion'] = $Occurrence.LastMajorReportVersion
                        $Result['LastMinorReportVersion'] = $Occurrence.LastMinorReportVersion
                        [PSCustomObject]$Result
                    }
                }
                else {
                    Write-Warning "No hardware inventory run found for $Computer"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMLastHardwareInventory.ps1' 69
#Region '.\Public\Get-CCMLastHeartbeat.ps1' 0
function Get-CCMLastHeartbeat {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    [Alias('Get-CCMLastDDR')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getLastDDRSplat = @{
            Namespace = 'root\CCM\InvAgt'
            Query     = "SELECT LastCycleStartedDate, LastReportDate, LastMajorReportVersion, LastMinorReportVersion, InventoryActionID FROM InventoryActionStatus WHERE InventoryActionID = '{00000000-0000-0000-0000-000000000003}'"
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$LastDDR = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getLastDDRSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getLastDDRSplat @connectionSplat
                    }
                }
                if ($LastDDR -is [Object] -and $LastDDR.Count -gt 0) {
                    foreach ($Occurrence in $LastDDR) {
                        $Result['LastCycleStartedDate'] = $Occurrence.LastCycleStartedDate
                        $Result['LastReportDate'] = $Occurrence.LastReportDate
                        $Result['LastMajorReportVersion'] = $Occurrence.LastMajorReportVersion
                        $Result['LastMinorReportVersion'] = $Occurrence.LastMinorReportVersion
                        [PSCustomObject]$Result
                    }
                }
                else {
                    Write-Warning "No Discovery Data Collection Cycle run found for $Computer"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMLastHeartbeat.ps1' 69
#Region '.\Public\Get-CCMLastScheduleTrigger.ps1' 0
function Get-CCMLastScheduleTrigger {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [parameter(Mandatory = $true, ParameterSetName = 'ByName-CimSession')]
        [parameter(Mandatory = $true, ParameterSetName = 'ByName-PSSession')]
        [parameter(Mandatory = $true, ParameterSetName = 'ByName-ComputerName')]
        [ValidateSet('Hardware Inventory',
            'Software Inventory',
            'Discovery Inventory',
            'File Collection',
            'IDMIF Collection',
            'Request Machine Assignments',
            'Evaluate Machine Policies',
            'Refresh Default MP Task',
            'LS (Location Service) Refresh Locations Task',
            'LS Timeout Refresh Task',
            'Policy Agent Request Assignment (User)',
            'Policy Agent Evaluate Assignment (User)',
            'Software Metering Generating Usage Report',
            'Source Update Message',
            'Clearing proxy settings cache',
            'Machine Policy Agent Cleanup',
            'User Policy Agent Cleanup',
            'Policy Agent Validate Machine Policy / Assignment',
            'Policy Agent Validate User Policy / Assignment',
            'Retrying/Refreshing certificates in AD on MP',
            'Peer DP Status reporting',
            'Peer DP Pending package check schedule',
            'SUM Updates install schedule',
            'Hardware Inventory Collection Cycle',
            'Software Inventory Collection Cycle',
            'Discovery Data Collection Cycle',
            'File Collection Cycle',
            'IDMIF Collection Cycle',
            'Software Metering Usage Report Cycle',
            'Windows Installer Source List Update Cycle',
            'Software Updates Policy Action Software Updates Assignments Evaluation Cycle',
            'PDP Maintenance Policy Branch Distribution Point Maintenance Task',
            'DCM policy',
            'Send Unsent State Message',
            'State System policy cache cleanout',
            'Update source policy',
            'Update Store Policy',
            'State system policy bulk send high',
            'State system policy bulk send low',
            'Application manager policy action',
            'Application manager user policy action',
            'Application manager global evaluation action',
            'Power management start summarizer',
            'Endpoint deployment reevaluate',
            'Endpoint AM policy reevaluate',
            'External event detection')]
        [string[]]$Schedule,
        [parameter(Mandatory = $true, ParameterSetName = 'ByID-CimSession')]
        [parameter(Mandatory = $true, ParameterSetName = 'ByID-PSSession')]
        [parameter(Mandatory = $true, ParameterSetName = 'ByID-ComputerName')]
        [string[]]$ScheduleID,
        [parameter(Mandatory = $false, ParameterSetName = 'ByID-CimSession')]
        [parameter(Mandatory = $false, ParameterSetName = 'ByID-PSSession')]
        [parameter(Mandatory = $false, ParameterSetName = 'ByID-ComputerName')]
        [switch]$ForceWildcard,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByName-CimSession')]
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByID-CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByName-ComputerName')]
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByID-ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [parameter(Mandatory = $true, ParameterSetName = 'ByName-PSSession')]
        [parameter(Mandatory = $true, ParameterSetName = 'ByID-PSSession')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [parameter(Mandatory = $true, ParameterSetName = 'ByName-ComputerName')]
        [parameter(Mandatory = $true, ParameterSetName = 'ByID-ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $ConnectionChecker = ($PSCmdlet.ParameterSetName).Split('-')[1]

        #region hashtable for mapping schedule names to IDs, and create CIM query
        $ScheduleTypeMap = @{
            'Hardware Inventory'                                                           = '{00000000-0000-0000-0000-000000000001}'
            'Software Inventory'                                                           = '{00000000-0000-0000-0000-000000000002}'
            'Discovery Inventory'                                                          = '{00000000-0000-0000-0000-000000000003}'
            'File Collection'                                                              = '{00000000-0000-0000-0000-000000000010}'
            'IDMIF Collection'                                                             = '{00000000-0000-0000-0000-000000000011}'
            'Request Machine Assignments'                                                  = '{00000000-0000-0000-0000-000000000021}'
            'Evaluate Machine Policies'                                                    = '{00000000-0000-0000-0000-000000000022}'
            'Refresh Default MP Task'                                                      = '{00000000-0000-0000-0000-000000000023}'
            'LS (Location Service) Refresh Locations Task'                                 = '{00000000-0000-0000-0000-000000000024}'
            'LS Timeout Refresh Task'                                                      = '{00000000-0000-0000-0000-000000000025}'
            'Policy Agent Request Assignment (User)'                                       = '{00000000-0000-0000-0000-000000000026}'
            'Policy Agent Evaluate Assignment (User)'                                      = '{00000000-0000-0000-0000-000000000027}'
            'Software Metering Generating Usage Report'                                    = '{00000000-0000-0000-0000-000000000031}'
            'Source Update Message'                                                        = '{00000000-0000-0000-0000-000000000032}'
            'Clearing proxy settings cache'                                                = '{00000000-0000-0000-0000-000000000037}'
            'Machine Policy Agent Cleanup'                                                 = '{00000000-0000-0000-0000-000000000040}'
            'User Policy Agent Cleanup'                                                    = '{00000000-0000-0000-0000-000000000041}'
            'Policy Agent Validate Machine Policy / Assignment'                            = '{00000000-0000-0000-0000-000000000042}'
            'Policy Agent Validate User Policy / Assignment'                               = '{00000000-0000-0000-0000-000000000043}'
            'Retrying/Refreshing certificates in AD on MP'                                 = '{00000000-0000-0000-0000-000000000051}'
            'Peer DP Status reporting'                                                     = '{00000000-0000-0000-0000-000000000061}'
            'Peer DP Pending package check schedule'                                       = '{00000000-0000-0000-0000-000000000062}'
            'SUM Updates install schedule'                                                 = '{00000000-0000-0000-0000-000000000063}'
            'Hardware Inventory Collection Cycle'                                          = '{00000000-0000-0000-0000-000000000101}'
            'Software Inventory Collection Cycle'                                          = '{00000000-0000-0000-0000-000000000102}'
            'Discovery Data Collection Cycle'                                              = '{00000000-0000-0000-0000-000000000103}'
            'File Collection Cycle'                                                        = '{00000000-0000-0000-0000-000000000104}'
            'IDMIF Collection Cycle'                                                       = '{00000000-0000-0000-0000-000000000105}'
            'Software Metering Usage Report Cycle'                                         = '{00000000-0000-0000-0000-000000000106}'
            'Windows Installer Source List Update Cycle'                                   = '{00000000-0000-0000-0000-000000000107}'
            'Software Updates Policy Action Software Updates Assignments Evaluation Cycle' = '{00000000-0000-0000-0000-000000000108}'
            'PDP Maintenance Policy Branch Distribution Point Maintenance Task'            = '{00000000-0000-0000-0000-000000000109}'
            'DCM policy'                                                                   = '{00000000-0000-0000-0000-000000000110}'
            'Send Unsent State Message'                                                    = '{00000000-0000-0000-0000-000000000111}'
            'State System policy cache cleanout'                                           = '{00000000-0000-0000-0000-000000000112}'
            'Update source policy'                                                         = '{00000000-0000-0000-0000-000000000113}'
            'Update Store Policy'                                                          = '{00000000-0000-0000-0000-000000000114}'
            'State system policy bulk send high'                                           = '{00000000-0000-0000-0000-000000000115}'
            'State system policy bulk send low'                                            = '{00000000-0000-0000-0000-000000000116}'
            'Application manager policy action'                                            = '{00000000-0000-0000-0000-000000000121}'
            'Application manager user policy action'                                       = '{00000000-0000-0000-0000-000000000122}'
            'Application manager global evaluation action'                                 = '{00000000-0000-0000-0000-000000000123}'
            'Power management start summarizer'                                            = '{00000000-0000-0000-0000-000000000131}'
            'Endpoint deployment reevaluate'                                               = '{00000000-0000-0000-0000-000000000221}'
            'Endpoint AM policy reevaluate'                                                = '{00000000-0000-0000-0000-000000000222}'
            'External event detection'                                                     = '{00000000-0000-0000-0000-000000000223}'
        }

        $RequestedSchedulesRaw = switch ($PSBoundParameters.Keys) {
            'Schedule' {
                foreach ($One in $Schedule) {
                    $ScheduleTypeMap[$One]
                }
            }
            'ScheduleID' {
                $ScheduleID
            }
        }
        $RequestedScheduleQuery = switch($ForceWildcard) {
            $true {
                switch ($RequestedSchedulesRaw -match '%') {
                    $true {
                        [string]::Format('SELECT * FROM CCM_Scheduler_History WHERE ScheduleID LIKE "{0}"', [string]::Join('" OR ScheduleID LIKE "', $RequestedSchedulesRaw))
                    }
                    $false {
                        [string]::Format('SELECT * FROM CCM_Scheduler_History WHERE ScheduleID LIKE "%{0}%"', [string]::Join('%" OR ScheduleID LIKE "%', $RequestedSchedulesRaw))
                    }
                }
            }
            $false {
                [string]::Format('SELECT * FROM CCM_Scheduler_History WHERE ScheduleID = "{0}"', [string]::Join('" OR ScheduleID = "', $RequestedSchedulesRaw))
            }
        }
        #endregion hashtable for mapping schedule names to IDs, and create CIM query

        $getSchedHistSplat = @{
            Namespace = 'root\CCM\Scheduler'
            Query     = $RequestedScheduleQuery
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $ConnectionChecker -ValueOnly -Scope Local)) {
            $getConnectionInfoSplat = @{
                $ConnectionChecker = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$ScheduleHistory = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getSchedHistSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getSchedHistSplat @connectionSplat
                    }
                }
                if ($ScheduleHistory -is [Object] -and $ScheduleHistory.Count -gt 0) {
                    foreach ($Trigger in $ScheduleHistory) {
                        $Result['ScheduleID'] = $Trigger.ScheduleID
                        $Result['Schedule'] = $ScheduleTypeMap.Keys.Where( { $ScheduleTypeMap[$_] -eq $Trigger.ScheduleID } )
                        $Result['UserSID'] = $Trigger.UserSID
                        $Result['FirstEvalTime'] = $Trigger.FirstEvalTime
                        $Result['ActivationMessageSent'] = $Trigger.ActivationMessageSent
                        $Result['ActivationMessageSentIsGMT'] = $Trigger.ActivationMessageSentIsGMT
                        $Result['ExpirationMessageSent'] = $Trigger.ExpirationMessageSent
                        $Result['ExpirationMessageSentIsGMT'] = $Trigger.ExpirationMessageSentIsGMT
                        $Result['LastTriggerTime'] = $Trigger.LastTriggerTime
                        $Result['TriggerState'] = $Trigger.TriggerState
                        [PSCustomObject]$Result
                    }
                }
                else {
                    Write-Warning "No triggered schedules found for [Query = '$RequestedScheduleQuery']"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMLastScheduleTrigger.ps1' 214
#Region '.\Public\Get-CCMLastSoftwareInventory.ps1' 0
function Get-CCMLastSoftwareInventory {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    [Alias('Get-CCMLastSINV')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getLastSINVSplat = @{
            Namespace = 'root\CCM\InvAgt'
            Query     = "SELECT LastCycleStartedDate, LastReportDate, LastMajorReportVersion, LastMinorReportVersion, InventoryActionID FROM InventoryActionStatus WHERE InventoryActionID = '{00000000-0000-0000-0000-000000000002}'"
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$LastSINV = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getLastSINVSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getLastSINVSplat @connectionSplat
                    }
                }
                if ($LastSINV -is [Object] -and $LastSINV.Count -gt 0) {
                    foreach ($Occurrence in $LastSINV) {
                        $Result['LastCycleStartedDate'] = $Occurrence.LastCycleStartedDate
                        $Result['LastReportDate'] = $Occurrence.LastReportDate
                        $Result['LastMajorReportVersion'] = $Occurrence.LastMajorReportVersion
                        $Result['LastMinorReportVersion'] = $Occurrence.LastMinorReportVersion
                        [PSCustomObject]$Result
                    }
                }
                else {
                    Write-Warning "No Software inventory run found for $Computer"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMLastSoftwareInventory.ps1' 69
#Region '.\Public\Get-CCMLoggingConfiguration.ps1' 0
function Get-CCMLoggingConfiguration {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getLogInfoSplat = @{
            Namespace   = 'root\ccm\policy\machine\actualconfig'
            ClassName   = 'CCM_Logging_GlobalConfiguration'
            ErrorAction = 'Stop'
        }
        $getLogLocationSplat = @{
            Property = 'LogDirectory'
            Key      = 'SOFTWARE\Microsoft\CCM\Logging\@Global'
            RegRoot  = 'HKEY_LOCAL_MACHINE'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$CimResult = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getLogInfoSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getLogInfoSplat @connectionSplat
                    }
                }
                if ($CimResult -is [Object] -and $CimResult.Count -gt 0) {
                    foreach ($Object in $CimResult) {
                        $Result['LogDirectory'] = (Get-CCMRegistryProperty @getLogLocationSplat @connectionSplat)[$Computer].LogDirectory
                        $Result['LogMaxSize'] = $Object.LogMaxSize
                        $Result['LogMaxHistory'] = $Object.LogMaxHistory
                        $Result['LogLevel'] = $Object.LogLevel
                        $Result['LogEnabled'] = $Object.LogEnabled
                        [PSCustomObject]$Result
                    }
                }
                else {
                    $Result['LogDirectory'] = $null
                    $Result['LogMaxSize'] = $null
                    $Result['LogMaxHistory'] = $null
                    $Result['LogLevel'] = $null
                    $Result['LogEnabled'] = $null
                    [PSCustomObject]$Result
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMLoggingConfiguration.ps1' 80
#Region '.\Public\Get-CCMMaintenanceWindow.ps1' 0
function Get-CCMMaintenanceWindow {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    [Alias('Get-CCMMW')]
    param (
        [parameter(Mandatory = $false)]
        [ValidateSet('All Deployment Service Window',
            'Program Service Window',
            'Reboot Required Service Window',
            'Software Update Service Window',
            'Task Sequences Service Window',
            'Corresponds to non-working hours')]
        [string[]]$MWType = @('All Deployment Service Window', 'Software Update Service Window'),
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region Create hashtable for mapping MW types, and create CIM filter based on input params
        $MW_Type = @{
            1    =    'All Deployment Service Window'
            2    =    'Program Service Window'
            3    =    'Reboot Required Service Window'
            4    =    'Software Update Service Window'
            5    =    'Task Sequences Service Window'
            6    =    'Corresponds to non-working hours'
        }

        $RequestedTypesRaw = $MW_Type.Keys.Where( { $MW_Type[$_] -in $MWType } )
        $RequestedTypesFilter = [string]::Format('Type = {0}', [string]::Join(' OR Type =', $RequestedTypesRaw))
        #endregion Create hashtable for mapping MW types, and create CIM filter based on input params

        $getMaintenanceWindowSplat = @{
            Namespace = 'root\CCM\ClientSDK'
            ClassName = 'CCM_ServiceWindow'
            Filter    = $RequestedTypesFilter
        }
        $getTimeZoneSplat = @{
            Query = 'SELECT Caption FROM Win32_TimeZone'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                $TZ = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getTimeZoneSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getTimeZoneSplat @connectionSplat
                    }
                }
                $Result['TimeZone'] = $TZ.Caption

                [ciminstance[]]$ServiceWindows = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getMaintenanceWindowSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getMaintenanceWindowSplat @connectionSplat
                    }
                }

                if ($ServiceWindows -is [Object] -and $ServiceWindows.Count -gt 0) {
                    foreach ($ServiceWindow in $ServiceWindows) {
                        $Result['StartTime'] = ($ServiceWindow.StartTime).ToUniversalTime()
                        $Result['EndTime'] = ($ServiceWindow.EndTime).ToUniversalTime()
                        $Result['Duration'] = $ServiceWindow.Duration
                        $Result['DurationDescription'] = Get-StringFromTimespan -Seconds $ServiceWindow.Duration
                        $Result['MWID'] = $ServiceWindow.ID
                        $Result['Type'] = $MW_Type.Item([int]$($ServiceWindow.Type))
                        [PSCustomObject]$Result
                    }
                }
                else {
                    $Result['StartTime'] = $null
                    $Result['EndTime'] = $null
                    $Result['Duration'] = $null
                    $Result['DurationDescription'] = $null
                    $Result['MWID'] = $null
                    $Result['Type'] = "No ServiceWindow of type(s) $([string]::Join(', ',$RequestedTypesRaw))"
                    [PSCustomObject]$Result
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMMaintenanceWindow.ps1' 114
#Region '.\Public\Get-CCMPackage.ps1' 0
function Get-CCMPackage {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false)]
        [string[]]$PackageID,
        [Parameter(Mandatory = $false)]
        [string[]]$PackageName,
        [Parameter(Mandatory = $false)]
        [string[]]$ProgramName,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
        $getPackageSplat = @{
            NameSpace = 'root\CCM\Policy\Machine\ActualConfig'
        }
        #endregion define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
    }
    process {

        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            try {
                $FilterParts = switch ($PSBoundParameters.Keys) {
                    'PackageID' {
                        [string]::Format('PKG_PackageID = "{0}"', [string]::Join('" OR PKG_PackageID = "', $PackageID))
                    }
                    'PackageName' {
                        [string]::Format('PKG_Name = "{0}"', [string]::Join('" OR PKG_Name = "', $PackageName))
                    }
                    'ProgramName' {
                        [string]::Format('PRG_ProgramName = "{0}"', [string]::Join('" OR PRG_ProgramName = "', $ProgramName))
                    }
                }
                $Filter = switch ($null -ne $FilterParts) {
                    $true {
                        [string]::Format(' WHERE {0}', [string]::Join(' OR ', $FilterParts))
                    }
                    $false {
                        ' '
                    }
                }
                $getPackageSplat['Query'] = [string]::Format('SELECT * FROM CCM_SoftwareDistribution{0}', $Filter)

                [ciminstance[]]$Packages = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getPackageSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getPackageSplat @connectionSplat
                    }
                }
                if ($Packages -is [Object] -and $Packages.Count -gt 0) {
                    Write-Output -InputObject $Packages
                }
                else {
                    Write-Warning "No deployed package found for $Computer based on input filters"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMPackage.ps1' 88
#Region '.\Public\Get-CCMPrimaryUser.ps1' 0
function Get-CCMPrimaryUser {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
        $getPrimaryUserSplat = @{
            NameSpace = 'root\CCM\CIModels'
            Query     = 'SELECT User from CCM_PrimaryUser'
        }
        #endregion define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$PrimaryUsers = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getPrimaryUserSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getPrimaryUserSplat @connectionSplat
                    }
                }
                if ($PrimaryUsers -is [Object] -and $PrimaryUsers.Count -gt 0) {
                    $Result['PrimaryUser'] = $PrimaryUsers.User
                    [PSCustomObject]$Result
                }
                else {
                    Write-Warning "No Primary Users found for $Computer"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMPrimaryUser.ps1' 65
#Region '.\Public\Get-CCMProvisioningMode.ps1' 0
function Get-CCMProvisioningMode {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getCIMRegistryPropertySplat = @{
            RegRoot  = 'HKEY_LOCAL_MACHINE'
            Key      = 'Software\Microsoft\CCM\CcmExec'
            Property = 'ProvisioningMode', 'ProvisioningEnabledTime', 'ProvisioningMaxMinutes'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Return = [ordered]@{ }
            $Return['ComputerName'] = $Computer
            try {
                $ProvisioningModeInfo = Get-CCMRegistryProperty @getCIMRegistryPropertySplat @connectionSplat
                if ($ProvisioningModeInfo -is [object]) {
                    $Return['ProvisioningMode'] = $ProvisioningModeInfo.$Computer.ProvisioningMode
                    $EnabledTime = switch ([string]::IsNullOrWhiteSpace($ProvisioningModeInfo.$Computer.ProvisioningEnabledTime)) {
                        $false {
                            [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($ProvisioningModeInfo.$Computer.ProvisioningEnabledTime))
                        }
                    }
                    $Return['ProvisioningEnabledTime'] = $EnabledTime
                    $Return['ProvisioningMaxMinutes'] = $ProvisioningModeInfo.$Computer.ProvisioningMaxMinutes
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
            [pscustomobject]$Return
        }
    }
}
#EndRegion '.\Public\Get-CCMProvisioningMode.ps1' 60
#Region '.\Public\Get-CCMRegistryProperty.ps1' 0
function Get-CCMRegistryProperty {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    [Alias('Get-CIMRegistryProperty')]
    param (
        [parameter(Mandatory = $true)]
        [ValidateSet('HKEY_LOCAL_MACHINE', 'HKEY_USERS', 'HKEY_CURRENT_CONFIG', 'HKEY_DYN_DATA', 'HKEY_CLASSES_ROOT', 'HKEY_CURRENT_USER')]
        [string]$RegRoot,
        [parameter(Mandatory = $true)]
        [string]$Key,
        [parameter(Mandatory = $false)]
        [string[]]$Property,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region create hash tables for translating values
        $RootKey = @{
            HKEY_CLASSES_ROOT   = 2147483648
            HKEY_CURRENT_USER   = 2147483649
            HKEY_LOCAL_MACHINE  = 2147483650
            HKEY_USERS          = 2147483651
            HKEY_CURRENT_CONFIG = 2147483653
            HKEY_DYN_DATA       = 2147483654
        }
        <#
            Maps the 'PropType' per property to the method we will invoke to get our return value.
            For example, if the 'type' is 1 (string) we have invoke the GetStringValue method to get our return data
        #>

        $RegPropertyMethod = @{
            1  = 'GetStringValue'
            2  = 'GetExpandedStringValue'
            3  = 'GetBinaryValue'
            4  = 'GetDWORDValue'
            7  = 'GetMultiStringValue'
            11 = 'GetQWORDValue'
        }

        <#
            Maps the 'PropType' per property to the property we will have to expand in our return value.
            For example, if the 'type' is 1 (string) we have to ExpandProperty sValue to get our return data
        #>

        $ReturnValName = @{
            1  = 'sValue'
            2  = 'sValue'
            3  = 'uValue'
            4  = 'uValue'
            7  = 'sValue'
            11 = 'uValue'
        }
        #endregion create hash tables for translating values

        # convert RootKey friendly name to the [uint32] equivalent so it can be used later
        $Root = $RootKey[$RegRoot]

        #region define our hash tables for parameters to pass to Invoke-CimMethod and our return hash table
        $EnumValuesSplat = @{
            Namespace = 'root\default'
            ClassName = 'StdRegProv'
        }
        #endregion define our hash tables for parameters to pass to Invoke-CimMethod and our return hash table
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Return = [ordered]@{ }
            $PerPC_Reg = [ordered]@{ }

            switch -regex ($ConnectionInfo.ConnectionType) {
                '^CimSession$|^ComputerName$' {
                    $EnumValuesSplat['MethodName'] = 'EnumValues'
                    $EnumValuesSplat['Arguments'] = @{
                        hDefKey     = [uint32]$Root
                        sSubKeyName = $Key
                    }
        
                    $EnumValues = Invoke-CimMethod @EnumValuesSplat @connectionSplat
        
                    switch ($PSBoundParameters.ContainsKey('Property')) {
                        $true {
                            $PropertiesToReturn = $Property
                        }
                        $false {
                            $PropertiesToReturn = $EnumValues.sNames
                        }
                    }
        
                    foreach ($PropertyName In $PropertiesToReturn) {
                        $PropIndex = $EnumValues.sNames.IndexOf($PropertyName)
                        switch ($PropIndex) {
                            -1 {
                                Write-Error ([string]::Format('Failed to find [Property = {0}] under [Key = {1}\{2}]', $PropertyName, $RegRoot, $Key))
                            }
                            default {
                                $PropType = $EnumValues.Types[$PropIndex]
                                $Prop = $ReturnValName[$PropType]
                                $Method = $RegPropertyMethod[$PropType]
                                $EnumValuesSplat['MethodName'] = $Method
                                $EnumValuesSplat['Arguments']['sValueName'] = $PropertyName
                                $PropertyValueQuery = Invoke-CimMethod @EnumValuesSplat @connectionSplat
        
                                switch ($PropertyValueQuery.ReturnValue) {
                                    0 {
                                        $PerPC_Reg.$PropertyName = $PropertyValueQuery.$Prop
                                        $Return[$Computer] = $([pscustomobject]$PerPC_Reg)
                                    }
                                    default {
                                        $Return[$Computer] = $null
                                        Write-Error ([string]::Format('Failed to resolve value [Property = {0}] [Key = {1}\{2}]', $PropertyName, $RegRoot, $Key))
                                    }
                                }
                            }
                        }
                    }
        
                }
                '^PSSession$' {
                    $RegPath = [string]::Format('registry::{0}\{1}', $RegRoot, $Key)
                    $PropertyFilter = switch ($PSBoundParameters.ContainsKey('Property')) {
                        $true {
                            [string]::Format("-Name '{0}'", [string]::Join("', '", $Property))
                        }
                        $false {
                            ' '
                        }
                    }
                    $ScriptBlockString = [string]::Format('Get-ItemProperty -Path "{0}" {1}', $RegPath, $PropertyFilter)
                    $ScriptBlock = [scriptblock]::Create($ScriptBlockString)
                    $InvokeCommandSplat = @{
                        ScriptBlock = $ScriptBlock
                    }

                    $RegData = Invoke-CCMCommand @InvokeCommandSplat @connectionSplat
                    switch ($PSBoundParameters.ContainsKey('Property')) {
                        $true {
                            switch ($Property) {
                                default {
                                    $PerPC_Reg.$PSItem = $RegData.$PSItem
                                }
                            }
                            $Return[$Computer] = $([pscustomobject]$PerPC_Reg)
                        }
                        $false {
                            $AllProperties = Get-Member -InputObject $RegData -MemberType NoteProperty

                            switch -regex ($AllProperties.Name) {
                                '^PSChildName$|^PSComputerName$|^PSParentPath$|^PSPath$|^PSProvider$|^PSShowComputerName$|^RunspaceId$' {
                                    continue
                                }
                                default {
                                    $PerPC_Reg.$PSItem = $RegData.$PSItem
                                }
                            }
                            $Return[$Computer] = $([pscustomobject]$PerPC_Reg)
                        }
                    }
                }
            }

            Write-Output $Return
        }
    }
}
#EndRegion '.\Public\Get-CCMRegistryProperty.ps1' 183
#Region '.\Public\Get-CCMServiceWindow.ps1' 0
function Get-CCMServiceWindow {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [parameter(Mandatory = $false)]
        [ValidateSet('All Deployment Service Window',
            'Program Service Window',
            'Reboot Required Service Window',
            'Software Update Service Window',
            'Task Sequences Service Window',
            'Corresponds to non-working hours')]
        [Alias('MWType')]
        [string[]]$SWType = @('All Deployment Service Window', 'Software Update Service Window'),
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region Create hashtable for mapping MW types, and create CIM filter based on input params
        $SW_Type = @{
            1    =    'All Deployment Service Window'
            2    =    'Program Service Window'
            3    =    'Reboot Required Service Window'
            4    =    'Software Update Service Window'
            5    =    'Task Sequences Service Window'
            6    =    'Corresponds to non-working hours'
        }

        $RequestedTypesRaw = $SW_Type.Keys.Where( { $SW_Type[$_] -in $SWType } )

        $RequestedTypesFilter = [string]::Format('ServiceWindowType = {0}', [string]::Join(' OR ServiceWindowType =', $RequestedTypesRaw))
        #endregion Create hashtable for mapping MW types, and create CIM filter based on input params
        $getServiceWindowSplat = @{
            Namespace = 'root\CCM\Policy\Machine\ActualConfig'
            ClassName = 'CCM_ServiceWindow'
            Filter    = $RequestedTypesFilter
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$ServiceWindows = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getServiceWindowSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getServiceWindowSplat @connectionSplat
                    }
                }
                if ($ServiceWindows -is [Object] -and $ServiceWindows.Count -gt 0) {
                    foreach ($ServiceWindow in $ServiceWindows) {
                        $Result['Schedules'] = $ServiceWindow.Schedules
                        $Result['ServiceWindowID'] = $ServiceWindow.ServiceWindowID
                        $Result['ServiceWindowType'] = $SW_Type.Item([int]$($ServiceWindow.ServiceWindowType))
                        [PSCustomObject]$Result
                    }
                }
                else {
                    $Result['Schedules'] = $null
                    $Result['ServiceWindowID'] = $null
                    $Result['ServiceWindowType'] = "No ServiceWindow of type(s) $([string]::Join(', ', $RequestedTypesRaw))"
                    [PSCustomObject]$Result
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMServiceWindow.ps1' 94
#Region '.\Public\Get-CCMSite.ps1' 0
function Get-CCMSite {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param(
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $GetSiteScriptblock = {
            $Client = New-Object -ComObject Microsoft.SMS.Client
            $Client.GetAssignedSite()
        }
        $invokeCommandSplat = @{
            ScriptBlock = $GetSiteScriptblock
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            $Result['SiteCode'] = switch ($Computer -eq $env:ComputerName) {
                $true {
                    $GetSiteScriptblock.Invoke()
                }
                $false {
                    Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                }
            }
            [pscustomobject]$Result
        }
    }
}
#EndRegion '.\Public\Get-CCMSite.ps1' 53
#Region '.\Public\Get-CCMSoftwareUpdate.ps1' 0
function Get-CCMSoftwareUpdate {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    [Alias('Get-CCMUpdate')]
    param(
        [Parameter(Mandatory = $false)]
        [switch]$IncludeDefs,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $EvaluationStateMap = @{
            23 = 'WaitForOrchestration'
            22 = 'WaitPresModeOff'
            21 = 'WaitingRetry'
            20 = 'PendingUpdate'
            19 = 'PendingUserLogoff'
            18 = 'WaitUserReconnect'
            17 = 'WaitJobUserLogon'
            16 = 'WaitUserLogoff'
            15 = 'WaitUserLogon'
            14 = 'WaitServiceWindow'
            13 = 'Error'
            12 = 'InstallComplete'
            11 = 'Verifying'
            10 = 'WaitReboot'
            9  = 'PendingHardReboot'
            8  = 'PendingSoftReboot'
            7  = 'Installing'
            6  = 'WaitInstall'
            5  = 'Downloading'
            4  = 'PreDownload'
            3  = 'Detecting'
            2  = 'Submitted'
            1  = 'Available'
            0  = 'None'
        }

        $ComplianceStateMap = @{
            0 = 'NotPresent'
            1 = 'Present'
            2 = 'PresenceUnknown/NotApplicable'
            3 = 'EvaluationError'
            4 = 'NotEvaluated'
            5 = 'NotUpdated'
            6 = 'NotConfigured'
        }
        #$UpdateStatus.Get_Item("$EvaluationState")
        #endregion status type hashtable

        $Filter = switch ($IncludeDefs) {
            $true {
                "ComplianceState=0"
            }
            Default {
                "NOT (Name LIKE '%Definition%' OR Name Like 'Security Intelligence Update%') and ComplianceState=0"
            }
        }

        $getUpdateSplat = @{
            Filter    = $Filter
            Namespace = 'root\CCM\ClientSDK'
            ClassName = 'CCM_SoftwareUpdate'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                [ciminstance[]]$MissingUpdates = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getUpdateSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getUpdateSplat @connectionSplat
                    }
                }
                if ($MissingUpdates -is [Object] -and $MissingUpdates.Count -gt 0) {
                    foreach ($Update in $MissingUpdates) {
                        $Result['ArticleID'] = $Update.ArticleID
                        $Result['BulletinID'] = $Update.BulletinID
                        $Result['ComplianceState'] = $ComplianceStateMap[[int]$($Update.ComplianceState)]
                        $Result['ContentSize'] = $Update.ContentSize
                        $Result['Deadline'] = $Update.Deadline
                        $Result['Description'] = $Update.Description
                        $Result['ErrorCode'] = $Update.ErrorCode
                        $Result['EvaluationState'] = $EvaluationStateMap[[int]$($Update.EvaluationState)]
                        $Result['ExclusiveUpdate'] = $Update.ExclusiveUpdate
                        $Result['FullName'] = $Update.FullName
                        $Result['IsUpgrade'] = $Update.IsUpgrade
                        $Result['MaxExecutionTime'] = $Update.MaxExecutionTime
                        $Result['Name'] = $Update.Name
                        $Result['NextUserScheduledTime'] = $Update.NextUserScheduledTime
                        $Result['NotifyUser'] = $Update.NotifyUser
                        $Result['OverrideServiceWindows'] = $Update.OverrideServiceWindows
                        $Result['PercentComplete'] = $Update.PercentComplete
                        $Result['Publisher'] = $Update.Publisher
                        $Result['RebootOutsideServiceWindows'] = $Update.RebootOutsideServiceWindows
                        $Result['RestartDeadline'] = $Update.RestartDeadline
                        $Result['StartTime'] = $Update.StartTime
                        $Result['UpdateID'] = $Update.UpdateID
                        $Result['URL'] = $Update.URL
                        $Result['UserUIExperience'] = $Update.UserUIExperience
                        [pscustomobject]$Result
                    }
                }
                else {
                    Write-Verbose "No updates found for $Computer"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMSoftwareUpdate.ps1' 140
#Region '.\Public\Get-CCMSoftwareUpdateGroup.ps1' 0
function Get-CCMSoftwareUpdateGroup {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    [Alias('Get-CCMSUG')]
    param(
        [Parameter(Mandatory = $false)]
        [string[]]$AssignmentName,
        [Parameter(Mandatory = $false)]
        [string[]]$AssignmentID,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getSUGSplat = @{
            Namespace = 'root\CCM\Policy\Machine\ActualConfig'
        }
        $getSUGComplianceSplat = @{
            Namespace = 'ROOT\ccm\SoftwareUpdates\DeploymentAgent'
        }

        $suppressRebootMap = @{
            0 = 'Not Suppressed'
            1 = 'Workstations Suppressed'
            2 = 'Servers Suppressed'
            3 = 'Workstations and Servers Suppressed'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                $FilterParts = switch ($PSBoundParameters.Keys) {
                    'AssignmentName' {
                        [string]::Format('AssignmentName = "{0}"', [string]::Join('" OR AssignmentName = "', $AssignmentName))
                    }
                    'AssignmentID' {
                        [string]::Format('AssignmentID = "{0}"', [string]::Join('" OR AssignmentID = "', $AssignmentID))
                    }
                }
                $Filter = switch ($null -ne $FilterParts) {
                    $true {
                        [string]::Format(' WHERE {0}', [string]::Join(' OR ', $FilterParts))
                    }
                    $false {
                        ' '
                    }
                }
                $getSUGSplat['Query'] = [string]::Format('SELECT * FROM CCM_UpdateCIAssignment{0}', $Filter)

                [ciminstance[]]$DeployedSUG = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getSUGSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getSUGSplat @connectionSplat
                    }
                }
                if ($DeployedSUG -is [Object] -and $DeployedSUG.Count -gt 0) {
                    foreach ($SUG in $DeployedSUG) {
                        $Result['AssignmentName'] = $SUG.AssignmentName

                        #region Query CCM_AssignmentCompliance to return SUG compliance
                        $getSUGComplianceSplat['Query'] = [string]::Format('SELECT IsCompliant FROM CCM_AssignmentCompliance WHERE AssignmentID = "{0}"', $SUG.AssignmentID)
                        $AssignmentCompliance = switch ($Computer -eq $env:ComputerName) {
                            $true {
                                Get-CimInstance @getSUGComplianceSplat @connectionSplat
                            }
                            $false {
                                Get-CCMCimInstance @getSUGComplianceSplat @connectionSplat
                            }
                        }
                        $Result['AssignmentCompliance'] = $AssignmentCompliance.IsCompliant
                        #endregion Query CCM_AssignmentCompliance to return SUG compliance

                        $Result['StartTime'] = $SUG.StartTime
                        $Result['EnforcementDeadline'] = $SUG.EnforcementDeadline
                        $Result['UseGMTTimes'] = $SUG.UseGMTTimes
                        $Result['NotifyUser'] = $SUG.NotifyUser
                        $Result['OverrideServiceWindows'] = $SUG.OverrideServiceWindows
                        $Result['RebootOutsideOfServiceWindows'] = $SUG.RebootOutsideOfServiceWindows
                        $Result['SuppressReboot'] = $suppressRebootMap[[int]$SUG.SuppressReboot]
                        $Result['UserUIExperience'] = $xml_Reserved1.SUMReserved.UserUIExperience
                        $Result['WoLEnabled'] = $SUG.WoLEnabled
                        # TODO - Determine if AssignmentAction needs figured out
                        $Result['AssignmentAction'] = $SUG.AssignmentAction
                        $Result['AssignmentFlags'] = $SUG.AssignmentFlags
                        $Result['AssignmentID'] = $SUG.AssignmentID
                        $Result['ConfigurationFlags'] = $SUG.ConfigurationFlags
                        $Result['DesiredConfigType'] = $SUG.DesiredConfigType
                        $Result['DisableMomAlerts'] = $SUG.DisableMomAlerts
                        $Result['DPLocality'] = $SUG.DPLocality
                        $Result['ExpirationTime'] = $SUG.ExpirationTime
                        $Result['LogComplianceToWinEvent'] = $SUG.LogComplianceToWinEvent
                        # ENHANCE - Parse NonComplianceCriticality
                        $Result['NonComplianceCriticality'] = $SUG.NonComplianceCriticality
                        $Result['PersistOnWriteFilterDevices'] = $SUG.PersistOnWriteFilterDevices
                        $Result['RaiseMomAlertsOnFailure'] = $SUG.RaiseMomAlertsOnFailure

                        #region store the 'Reserved1' property of the SUG as XML so we can parse the properties
                        [xml]$xml_Reserved1 = $SUG.Reserved1
                        $Result['StateMessageVerbosity'] = $xml_Reserved1.SUMReserved.StateMessageVerbosity
                        $Result['LimitStateMessageVerbosity'] = $xml_Reserved1.SUMReserved.LimitStateMessageVerbosity
                        $Result['UseBranchCache'] = $xml_Reserved1.SUMReserved.UseBranchCache
                        $Result['RequirePostRebootFullScan'] = $xml_Reserved1.SUMReserved.RequirePostRebootFullScan
                        #endregion store the 'Reserved1' property of the SUG as XML so we can parse the properties

                        $Result['SendDetailedNonComplianceStatus'] = $SUG.SendDetailedNonComplianceStatus
                        $Result['SettingTypes'] = $SUG.SettingTypes
                        $Result['SoftDeadlineEnabled'] = $SUG.SoftDeadlineEnabled
                        $Result['StateMessagePriority'] = $SUG.StateMessagePriority
                        $Result['UpdateDeadline'] = $SUG.UpdateDeadline
                        $Result['UseSiteEvaluation'] = $SUG.UseSiteEvaluation
                        $Result['Reserved2'] = $SUG.Reserved2
                        $Result['Reserved3'] = $SUG.Reserved3
                        $Result['Reserved4'] = $SUG.Reserved4
                        #region loop through the AssignedCIs and cast them as XML so they can be easily work with
                        $Result['AssignedCIs'] = foreach ($AssignCI in $SUG.AssignedCIs) {
                            ([xml]$AssignCI).CI
                        }
                        #endregion loop through the AssignedCIs and cast them as XML so they can be easily work with

                        [pscustomobject]$Result
                    }
                }
                else {
                    Write-Verbose "No deployed SUGs found for $Computer"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMSoftwareUpdateGroup.ps1' 158
#Region '.\Public\Get-CCMSoftwareUpdateSettings.ps1' 0
function Get-CCMSoftwareUpdateSettings {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param(
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
            )
    begin {
        $getSoftwareUpdateSettingsSplat = @{
            Namespace = 'root\CCM\Policy\Machine\ActualConfig'
            Query     = 'SELECT * FROM CCM_SoftwareUpdatesClientConfig'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            [ciminstance[]]$Settings = switch ($Computer -eq $env:ComputerName) {
                $true {
                    Get-CimInstance @getSoftwareUpdateSettingsSplat @connectionSplat
                }
                $false {
                    Get-CCMCimInstance @getSoftwareUpdateSettingsSplat @connectionSplat
                }
            }
            if ($Settings -is [Object] -and $Settings.Count -gt 0) {
                foreach ($Setting in $Settings) {
                    $Result['ComponentName'] = $Setting.ComponentName
                    $Result['Enabled'] = $Setting.Enabled
                    $Result['WUfBEnabled'] = $Setting.WUfBEnabled
                    $Result['EnableThirdPartyUpdates'] = $Setting.EnableThirdPartyUpdates
                    $Result['EnableExpressUpdates'] = $Setting.EnableExpressUpdates
                    $Result['ServiceWindowManagement'] = $Setting.ServiceWindowManagement
                    $Result['ReminderInterval'] = $Setting.ReminderInterval
                    $Result['DayReminderInterval'] = $Setting.DayReminderInterval
                    $Result['HourReminderInterval'] = $Setting.HourReminderInterval
                    $Result['AssignmentBatchingTimeout'] = $Setting.AssignmentBatchingTimeout
                    $Result['BrandingSubTitle'] = $Setting.BrandingSubTitle
                    $Result['BrandingTitle'] = $Setting.BrandingTitle
                    $Result['ContentDownloadTimeout'] = $Setting.ContentDownloadTimeout
                    $Result['ContentLocationTimeout'] = $Setting.ContentLocationTimeout
                    $Result['DynamicUpdateOption'] = $Setting.DynamicUpdateOption
                    $Result['ExpressUpdatesPort'] = $Setting.ExpressUpdatesPort
                    $Result['ExpressVersion'] = $Setting.ExpressVersion
                    $Result['GroupPolicyNotificationTimeout'] = $Setting.GroupPolicyNotificationTimeout
                    $Result['MaxScanRetryCount'] = $Setting.MaxScanRetryCount
                    $Result['NEOPriorityOption'] = $Setting.NEOPriorityOption
                    $Result['PerDPInactivityTimeout'] = $Setting.PerDPInactivityTimeout
                    $Result['ScanRetryDelay'] = $Setting.ScanRetryDelay
                    $Result['SiteSettingsKey'] = $Setting.SiteSettingsKey
                    $Result['TotalInactivityTimeout'] = $Setting.TotalInactivityTimeout
                    $Result['UserJobPerDPInactivityTimeout'] = $Setting.UserJobPerDPInactivityTimeout
                    $Result['UserJobTotalInactivityTimeout'] = $Setting.UserJobTotalInactivityTimeout
                    $Result['WSUSLocationTimeout'] = $Setting.WSUSLocationTimeout
                    $Result['Reserved1'] = $Setting.Reserved1
                    $Result['Reserved2'] = $Setting.Reserved2
                    $Result['Reserved3'] = $Setting.Reserved3
                    [pscustomobject]$Result
                }
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMSoftwareUpdateSettings.ps1' 85
#Region '.\Public\Get-CCMTaskSequence.ps1' 0
function Get-CCMTaskSequence {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false)]
        [string[]]$PackageID,
        [Parameter(Mandatory = $false)]
        [string[]]$TaskSequenceName,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
        $getPackageSplat = @{
            NameSpace = 'root\CCM\Policy\Machine\ActualConfig'
        }
        #endregion define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            try {
                $FilterParts = switch ($PSBoundParameters.Keys) {
                    'PackageID' {
                        [string]::Format('PKG_PackageID = "{0}"', [string]::Join('" OR PRG_ProgramName = "', $PackageID))
                    }
                    'TaskSequenceName' {
                        [string]::Format('PKG_Name = "{0}"', [string]::Join('" OR PKG_Name = "', $TaskSequenceName))
                    }
                }
                $Filter = switch ($null -ne $FilterParts) {
                    $true {
                        [string]::Format(' WHERE {0}', [string]::Join(' OR ', $FilterParts))
                    }
                    $false {
                        ' '
                    }
                }
                $getPackageSplat['Query'] = [string]::Format('SELECT * FROM CCM_TaskSequence{0}', $Filter)

                [ciminstance[]]$Packages = switch ($Computer -eq $env:ComputerName) {
                    $true {
                        Get-CimInstance @getPackageSplat @connectionSplat
                    }
                    $false {
                        Get-CCMCimInstance @getPackageSplat @connectionSplat
                    }
                }
                if ($Packages -is [Object] -and $Packages.Count -gt 0) {
                    Write-Output -InputObject $Packages
                }
                else {
                    Write-Warning "No deployed task sequences found for $Computer based on input filters"
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Get-CCMTaskSequence.ps1' 82
#Region '.\Public\Invoke-CCMApplication.ps1' 0
Function Invoke-CCMApplication {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    Param
    (
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [string[]]$ID,
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [bool[]]$IsMachineTarget,
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [string[]]$Revision,
        [Parameter(Mandatory = $true)]
        [ValidateSet('Install', 'Uninstall')]
        [Alias('Action')]
        [string]$Method,
        [Parameter(Mandatory = $false)]
        [ValidateSet('Immediate', 'NonBusinessHours', 'AdminSchedule')]
        [string]$EnforcePreference = 'Immediate',
        [Parameter(Mandatory = $false)]
        [ValidateSet('Foreground', 'High', 'Normal', 'Low')]
        [string]$Priority = 'High',
        [Parameter(Mandatory = $false)]
        [bool]$IsRebootIfNeeded = $false,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $EnforcePreferenceMap = @{
            'Immediate'        = [uint32]0
            'NonBusinessHours' = [uint32]1
            'AdminSchedule'    = [uint32]2
        }
        $invokeAppMethodSplat = @{
            NameSpace  = 'root\CCM\ClientSDK'
            ClassName  = 'CCM_Application'
            MethodName = $Method
            Arguments  = @{
                Priority          = $Priority
                EnforcePreference = $EnforcePreferenceMap[$EnforcePreference]
                IsRebootIfNeeded  = $IsRebootIfNeeded
            }
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer
            $Result['AppMethodInvoked'] = $false

            foreach ($AppID in $ID) {
                if ($PSCmdlet.ShouldProcess("[Method = '$Method'] [ID = '$AppID'] [ComputerName = '$Computer']", "Invoke-CCMApplication")) {
                    $invokeAppMethodSplat.Arguments['ID'] = [string]$AppID
                    $invokeAppMethodSplat.Arguments['Revision'] = [string]$Revision
                    $invokeAppMethodSplat.Arguments['IsMachineTarget'] = [bool]$IsMachineTarget
                    try {
                        $Invocation = switch -regex ($ConnectionInfo.ConnectionType) {
                            '^CimSession$|^ComputerName$' {
                                Invoke-CimMethod @invokeAppMethodSplat @connectionSplat
                            }
                            '^PSSession$' {
                                $InvokeCommandSplat = @{
                                    ArgumentList = $invokeAppMethodSplat
                                    ScriptBlock  = {
                                        param($invokeAppMethodSplat)
                                        Invoke-CimMethod @invokeAppMethodSplat
                                    }
                                }
                                Invoke-CCMCommand @InvokeCommandSplat @connectionSplat
                            }
                        }

                        switch ($Invocation.ReturnValue) {
                            0 {
                                $Result['AppMethodInvoked'] = $true
                            }
                        }
                    }
                    catch {
                        Write-Error "Failed to invoke [Method = '$Method'] [ID = '$AppID'] [ComputerName = '$Computer'] - $($_.Exception.Message)"
                    }
                    [pscustomobject]$Result
                }
            }
        }
    }
}
#EndRegion '.\Public\Invoke-CCMApplication.ps1' 107
#Region '.\Public\Invoke-CCMBaseline.ps1' 0
function Invoke-CCMBaseline {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [string[]]$BaselineName = 'NotSpecified',
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region Setup our *-CIM* parameters that will apply to the CIM cmdlets in use based on input parameters
        $getBaselineSplat = @{
            Namespace   = 'root\ccm\dcm'
            ErrorAction = 'Stop'
        }
        $invokeBaselineEvalSplat = @{
            Namespace   = 'root\ccm\dcm'
            ClassName   = 'SMS_DesiredConfiguration'
            ErrorAction = 'Stop'
            Name        = 'TriggerEvaluation'
        }
        #endregion Setup our common *-CIM* parameters that will apply to the CIM cmdlets in use based on input parameters

        #region hash table for translating compliance status
        $LastComplianceStatus = @{
            0 = 'Non-Compliant'
            1 = 'Compliant'
            2 = 'Compliance State Unknown'
            4 = 'Error'
        }
        #endregion hash table for translating compliance status

        <#
            Not all Properties are on all Configuration Baseline instances, this is the list of possible options
            We will identify which properties exist, and pass the respective arguments to Invoke-CimMethod with typecasting
        #>

        $PropertyOptions = 'IsEnforced', 'IsMachineTarget', 'Name', 'PolicyType', 'Version'
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            foreach ($BLName in $BaselineName) {
                #region Query CIM for Configuration Baselines based off DisplayName
                $BLQuery = switch ($PSBoundParameters.ContainsKey('BaselineName')) {
                    $true {
                        [string]::Format("SELECT * FROM SMS_DesiredConfiguration WHERE DisplayName = '{0}'", $BLName)
                    }
                    $false {
                        "SELECT * FROM SMS_DesiredConfiguration"
                    }
                }
                Write-Verbose "Checking for Configuration Baselines on [ComputerName='$Computer'] with [Query=`"$BLQuery`"]"
                $getBaselineSplat['Query'] = $BLQuery
                try {
                    $Baselines = switch -regex ($ConnectionInfo.ConnectionType) {
                        '^ComputerName$|^CimSession$' {
                            Get-CimInstance @getBaselineSplat @connectionSplat
                        }
                        'PSSession' {
                            Get-CCMCimInstance @getBaselineSplat @connectionSplat
                        }
                    }
                }
                catch {
                    # need to improve this - should catch access denied vs RPC, and need to do this on ALL CIM related queries across the module.
                    # Maybe write a function???
                    Write-Error "Failed to query for baselines on $Computer - $_"
                }
                #endregion Query CIM for Configuration Baselines based off DisplayName

                #region Based on results of CIM Query, identify arguments and invoke TriggerEvaluation
                switch ($null -eq $Baselines) {
                    $false {
                        foreach ($BL in $Baselines) {
                            if ($PSCmdlet.ShouldProcess($BL.DisplayName, "Invoke Evaluation")) {
                                $Return = [ordered]@{ }
                                $Return['ComputerName'] = $Computer
                                $Return['BaselineName'] = $BL.DisplayName
                                $Return['Version'] = $BL.Version
                                $Return['LastComplianceStatus'] = $LastComplianceStatus[[int]$BL.LastComplianceStatus]
                                $Return['LastEvalTime'] = $BL.LastEvalTime

                                #region generate a property list of existing arguments to pass to the TriggerEvaluation method. Type is important!
                                $ArgumentList = @{ }
                                foreach ($Property in $PropertyOptions) {
                                    $PropExist = Get-Member -InputObject $BL -MemberType Properties -Name $Property
                                    switch ($PropExist) {
                                        $null {
                                            continue
                                        }
                                        default {
                                            $TypeString = ($PropExist.Definition.Split(' '))[0]
                                            $Type = [scriptblock]::Create("[$TypeString]")
                                            $ArgumentList[$Property] = $BL.$Property -as (. $Type)
                                        }
                                    }
                                }
                                $invokeBaselineEvalSplat['Arguments'] = $ArgumentList
                                #endregion generate a property list of existing arguments to pass to the TriggerEvaluation method. Type is important!

                                #region Trigger the Configuration Baseline to run
                                Write-Verbose "Identified the Configuration Baseline [BaselineName='$($BL.DisplayName)'] on [ComputerName='$Computer'] will trigger via the 'TriggerEvaluation' CIM method"
                                $Return['Invoked'] = try {
                                    $Invocation = switch -regex ($ConnectionInfo.ConnectionType) {
                                        '^ComputerName$|^CimSession$' {
                                            Invoke-CimMethod @invokeBaselineEvalSplat @connectionSplat
                                        }
                                        'PSSession' {
                                            $InvokeCCMCommandSplat = @{
                                                Arguments   = $invokeBaselineEvalSplat
                                                ScriptBlock = {
                                                    param(
                                                        $invokeBaselineEvalSplat
                                                    )
                                                    Invoke-CimMethod @invokeBaselineEvalSplat
                                                }
                                            }
                                            Invoke-CCMCommand @InvokeCCMCommandSplat @connectionSplat

                                        }
                                    }
                                    switch ($Invocation.ReturnValue) {
                                        0 {
                                            $true
                                        }
                                        default {
                                            $false
                                        }
                                    }
                                }
                                catch {
                                    $false
                                }

                                [pscustomobject]$Return
                                #endregion Trigger the Configuration Baseline to run
                            }
                        }
                    }
                    $true {
                        Write-Warning "Failed to identify any Configuration Baselines on [ComputerName='$Computer'] with [Query=`"$BLQuery`"]"
                    }
                }
                #endregion Based on results of CIM Query, identify arguments and invoke TriggerEvaluation
            }
        }
    }
}
#EndRegion '.\Public\Invoke-CCMBaseline.ps1' 168
#Region '.\Public\Invoke-CCMClientAction.ps1' 0
function Invoke-CCMClientAction {
    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'ComputerName')]
    param
    (
        [parameter(Mandatory = $true)]
        [ValidateSet('HardwareInv', 'FullHardwareInv', 'SoftwareInv', 'UpdateScan', 'UpdateEval', 'MachinePol', 'AppEval', 'DDR', 'RefreshDefaultMP', 'SourceUpdateMessage', 'SendUnsentStateMessage')]
        [ValidateNotNullOrEmpty()]
        [string[]]$Schedule,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $invokeClientActionSplat = @{
            MethodName  = 'TriggerSchedule'
            Namespace   = 'root\ccm'
            ClassName   = 'sms_client'
            ErrorAction = 'Stop'
        }

        $getFullHINVSplat = @{
            Namespace   = 'root\ccm\invagt'
            ClassName   = 'InventoryActionStatus'
            ErrorAction = 'Stop'
            Filter      = "InventoryActionID ='{00000000-0000-0000-0000-000000000001}'"
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            foreach ($Option in $Schedule) {
                if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer'] [Schedule = '$Option']", "Invoke Schedule")) {
                    $Result['Action'] = $Option
                    $Result['Invoked'] = $false
                    $Action = switch -Regex ($Option) {
                        '^HardwareInv$|^FullHardwareInv$' {
                            '{00000000-0000-0000-0000-000000000001}'
                        }
                        'SoftwareInv' {
                            '{00000000-0000-0000-0000-000000000002}'
                        }
                        'UpdateScan' {
                            '{00000000-0000-0000-0000-000000000113}'
                        }
                        'UpdateEval' {
                            '{00000000-0000-0000-0000-000000000108}'
                        }
                        'MachinePol' {
                            '{00000000-0000-0000-0000-000000000021}'
                        }
                        'AppEval' {
                            '{00000000-0000-0000-0000-000000000121}'
                        }
                        'DDR' {
                            '{00000000-0000-0000-0000-000000000003}'
                        }
                        'RefreshDefaultMP' {
                            '{00000000-0000-0000-0000-000000000023}'
                        }
                        'SourceUpdateMessage' {
                            '{00000000-0000-0000-0000-000000000032}'
                        }
                        'SendUnsentStateMessage' {
                            '{00000000-0000-0000-0000-000000000111}'
                        }
                    }

                    $invokeClientActionSplat['Arguments'] =  @{
                        sScheduleID = $Action
                    }

                    try {
                        $Invocation = switch ($Computer -eq $env:ComputerName) {
                            $true {
                                if ($Option -eq 'FullHardwareInv') {
                                    Write-Verbose "Attempting to delete Hardware Inventory history for $Computer as a FullHardwareInv was requested"
                                    $HWInv = Get-CimInstance @getFullHINVSplat @connectionSplat
                                    if ($null -ne $HWInv) {
                                        Remove-CimInstance -InputObject $HWInv
                                        Write-Verbose "Hardware Inventory history deleted for $Computer"
                                    }
                                    else {
                                        Write-Verbose "No Hardware Inventory history to delete for $Computer"
                                    }
                                }

                                Write-Verbose "Triggering a $Option Cycle on $Computer via the 'TriggerSchedule' CIM method"
                                Invoke-CimMethod @invokeClientActionSplat
                            }
                            $false {
                                $invokeCommandSplat = @{ }

                                if ($Option -eq 'FullHardwareInv') {
                                    $invokeCommandSplat['ScriptBlock'] = {
                                        param($getFullHINVSplat)
                                        $HWInv = Get-CimInstance @getFullHINVSplat
                                        if ($null -ne $HWInv) {
                                            Remove-CimInstance -InputObject $HWInv
                                        }
                                    }
                                    $invokeCommandSplat['ArgumentList'] = $getFullHINVSplat
                                    Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                                }

                                $invokeCommandSplat['ScriptBlock'] = {
                                    param($invokeClientActionSplat)
                                    Invoke-CimMethod @invokeClientActionSplat
                                }
                                $invokeCommandSplat['ArgumentList'] = $invokeClientActionSplat
                                Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                            }
                        }
                    }
                    catch [System.UnauthorizedAccessException] {
                        Write-Error -Message "Access denied to $Computer" -Category AuthenticationError -Exception $_.Exception
                    }
                    catch {
                        Write-Warning "Failed to invoke the $Option cycle via CIM. Error: $($_.Exception.Message)"
                    }
                    if ($Invocation) {
                        Write-Verbose "Successfully invoked the $Option Cycle on $Computer via the 'TriggerSchedule' CIM method"
                        $Result['Invoked'] = $true
                    }
                    [pscustomobject]$Result
                }
            }
        }
    }
}
#EndRegion '.\Public\Invoke-CCMClientAction.ps1' 152
#Region '.\Public\Invoke-CCMCommand.ps1' 0
function Invoke-CCMCommand {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param
    (
        [Parameter(Mandatory = $true)]
        [scriptblock]$ScriptBlock,
        [Parameter(Mandatory = $false)]
        [string[]]$FunctionsToLoad,
        [Parameter(Mandatory = $false)]
        [object[]]$ArgumentList,
        [Parameter(Mandatory = $false, ParameterSetName = 'CimSession')]
        [ValidateRange(1000, 900000)]
        [int32]$Timeout = 120000,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference = 'CimSession'
    )
    begin {
        $HelperFunctions = switch ($PSBoundParameters.ContainsKey('FunctionsToLoad')) {
            $true {
                Convert-FunctionToString -FunctionToConvert $FunctionsToLoad
            }
        }
        $ConnectionChecker = switch ($PSCmdlet.ParameterSetName) {
            'ComputerName' {
                $ConnectionPreference
            }
            default {
                $PSCmdlet.ParameterSetName
            }
        }
        switch ($ConnectionChecker) {
            'CimSession' {
                $invokeCommandSplat = @{
                    ClassName  = 'Win32_Process'
                    MethodName = 'Create'
                }
                $PipeName = [guid]::NewGuid().Guid
                $ArgList = switch ($PSBoundParameters.ContainsKey('ArgumentList')) {
                    $true {
                        $SupportFunctionsToConvert = 'ConvertTo-CCMCodeStringFromObject', 'ConvertFrom-CliXml', 'ConvertFrom-CCMCodeStringToObject'
                        $PassArgList = $true
                        ConvertTo-CCMCodeStringFromObject -inputObject $ArgumentList
                    }
                    $false {
                        $SupportFunctionsToConvert = 'ConvertTo-CCMCodeStringFromObject'
                        $PassArgList = $false
                        [string]::Empty
                    }
                }
                $SupportFunctions = Convert-FunctionToString -FunctionToConvert $SupportFunctionsToConvert
                $ScriptBlockString = [string]::Format(@'
        {0}
 
        {2}
 
        $namedPipe = New-Object System.IO.Pipes.NamedPipeServerStream "{1}", "Out"
        $namedPipe.WaitForConnection()
        $streamWriter = New-Object System.IO.StreamWriter $namedPipe
        $streamWriter.AutoFlush = $true
        $ScriptBlock = {{
            {3}
        }}
        $TempResultPreConversion = switch([bool]${4}) {{
            $true {{
                $ScriptBlock.Invoke((ConvertFrom-CCMCodeStringToObject -inputString {5}))
            }}
            $false {{
                $ScriptBlock.Invoke()
            }}
        }}
        $results = ConvertTo-CCMCodeStringFromObject -inputObject $TempResultPreConversion
        $streamWriter.WriteLine("$($results)")
        $streamWriter.dispose()
        $namedPipe.dispose()
'@
 , $SupportFunctions, $PipeName, $HelperFunctions, $ScriptBlock, $PassArgList, $ArgList)

                $scriptBlockPreEncoded = [scriptblock]::Create($ScriptBlockString)
                $byteCommand = [System.Text.encoding]::UTF8.GetBytes($scriptBlockPreEncoded)
                $encodedScriptBlock = [convert]::ToBase64string($byteCommand)
                $invokeCommandSplat['Arguments'] = @{
                    CommandLine = [string]::Format("powershell.exe (invoke-command ([scriptblock]::Create([system.text.encoding]::UTF8.GetString([System.convert]::FromBase64string('{0}')))))", $encodedScriptBlock)
                }
            }
            'PSSession' {
                $ScriptBlockString = [string]::Format(@'
                {0}
 
                {1}
'@
 , $HelperFunctions, $ScriptBlock)
                $FullScriptBlock = [scriptblock]::Create($ScriptBlockString)

                $InvokeCommandSplat = @{
                    ScriptBlock = $FullScriptBlock
                }
                switch ($PSBoundParameters.ContainsKey('ArgumentList')) {
                    $true {
                        $invokeCommandSplat['ArgumentList'] = $ArgumentList
                    }
                }
            }
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly -Scope Local)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat -Prefer $ConnectionChecker
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            switch ($ConnectionChecker) {
                'CimSession' {
                    $null = Invoke-CimMethod @invokeCommandSplat @connectionSplat

                    $namedPipe = New-Object System.IO.Pipes.NamedPipeClientStream $Computer, "$($PipeName)", "In"
                    $namedPipe.Connect($timeout)
                    $streamReader = New-Object System.IO.StreamReader $namedPipe
        
                    while ($null -ne ($data = $streamReader.ReadLine())) {
                        $tempData = $data
                    }
        
                    $streamReader.dispose()
                    $namedPipe.dispose()
        
                    if (-not [string]::IsNullOrWhiteSpace($tempData)) {
                        ConvertFrom-CCMCodeStringToObject -inputString $tempData
                    }
                }
                'PSSession' {
                    Invoke-Command @InvokeCommandSplat @connectionSplat
                }
            }
        }
    }
}
#EndRegion '.\Public\Invoke-CCMCommand.ps1' 147
#Region '.\Public\Invoke-CCMPackage.ps1' 0
function Invoke-CCMPackage {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [Alias('PKG_PackageID')]
        [string[]]$PackageID,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [Alias('PKG_Name')]
        [string[]]$PackageName,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [Alias('PRG_ProgramName')]
        [string[]]$ProgramName,
        [Parameter(Mandatory = $false)]
        [switch]$Force,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    Begin {
        $setAlwaysRerunSplat = @{
            Property = @{
                ADV_RepeatRunBehavior    = 'RerunAlways'
                ADV_MandatoryAssignments = $true
            }
        }

        #region define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
        $getPackageSplat = @{
            NameSpace = 'root\CCM\Policy\Machine\ActualConfig'
        }
        #endregion define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
    }
    process {
        # temp fix for when PSComputerName from pipeline is empty - we assume it is $env:ComputerName
        switch ($PSCmdlet.ParameterSetName) {
            'ComputerName' {
                switch ([string]::IsNullOrWhiteSpace($ComputerName)) {
                    $true {
                        $ComputerName = $env:ComputerName
                    }
                }
            }
        }
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer']", "Invoke-CCMPackage")) {
                try {
                    $FilterParts = switch ($PSBoundParameters.Keys) {
                        'PackageID' {
                            [string]::Format('PKG_PackageID = "{0}"', [string]::Join('" OR PRG_ProgramName = "', $PackageID))
                        }
                        'PackageName' {
                            [string]::Format('PKG_Name = "{0}"', [string]::Join('" OR PKG_Name = "', $PackageName))
                        }
                        'ProgramName' {
                            [string]::Format('PRG_ProgramName = "{0}"', [string]::Join('" OR PRG_ProgramName = "', $ProgramName))
                        }
                    }
                    $Filter = switch ($null -ne $FilterParts) {
                        $true {
                            [string]::Format(' WHERE {0}', [string]::Join(' OR ', $FilterParts))
                        }
                        $false {
                            ' '
                        }
                    }
                    $getPackageSplat['Query'] = [string]::Format('SELECT * FROM CCM_SoftwareDistribution{0}', $Filter)

                    [ciminstance[]]$Packages = switch ($Computer -eq $env:ComputerName) {
                        $true {
                            Get-CimInstance @getPackageSplat @connectionSplat
                        }
                        $false {
                            Get-CCMCimInstance @getPackageSplat @connectionSplat
                        }
                    }
                    if ($Packages -is [Object] -and $Packages.Count -gt 0) {
                        foreach ($Advertisement in $Packages) {
                            switch ($Force.IsPresent) {
                                $true {
                                    Write-Verbose "Force parameter present - Setting package to always rerun"
                                    $setAlwaysRerunSplat['InputObject'] = $Advertisement
                                    switch -regex ($ConnectionInfo.ConnectionType) {
                                        '^ComputerName$|^CimSession$' {
                                            Set-CimInstance @setAlwaysRerunSplat @connectionSplat
                                        }
                                        'PSSession' {
                                            $invokeCommandSplat = @{
                                                ScriptBlock  = {
                                                    param (
                                                        $setAlwaysRerunSplat
                                                    )
                                                    Set-CimInstance @setAlwaysRerunSplat
                                                }
                                                ArgumentList = $setAlwaysRerunSplat
                                            }
                                            Invoke-Command @invokeCommandSplat @connectionSplat
                                        }
                                    }
                                }
                            }
                            $getPackageSplat['Query'] = [string]::Format("SELECT ScheduledMessageID FROM CCM_Scheduler_ScheduledMessage WHERE ScheduledMessageID LIKE '{0}%'", $Advertisement.ADV_AdvertisementID)
                            $ScheduledMessageID = switch ($Computer -eq $env:ComputerName) {
                                $true {
                                    Get-CimInstance @getPackageSplat @connectionSplat
                                }
                                $false {
                                    Get-CCMCimInstance @getPackageSplat @connectionSplat
                                }
                            }
                            if ($null -ne $ScheduledMessageID) {
                                Invoke-CCMTriggerSchedule -ScheduleID $ScheduledMessageID.ScheduledMessageID @connectionSplat
                            }
                            else {
                                Write-Warning "No ScheduledMessageID found for $Computer based on input filters"
                            }
                        }
                    }
                    else {
                        Write-Warning "No deployed package found for $Computer based on input filters"
                    }
                }
                catch {
                    $ErrorMessage = $_.Exception.Message
                    Write-Error $ErrorMessage
                }
            }
        }
    }
}
#EndRegion '.\Public\Invoke-CCMPackage.ps1' 153
#Region '.\Public\Invoke-CCMResetPolicy.ps1' 0
function Invoke-CCMResetPolicy {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false)]
        [ValidateSet('Purge', 'ForceFull')]
        [string]$ResetType = 'Purge',
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $uFlags = switch ($ResetType) {
            'Purge' {
                1
            }
            'ForceFull' {
                0
            }
        }
        $policyResetSplat = @{
            MethodName = 'ResetPolicy'
            Namespace  = 'root\ccm'
            ClassName  = 'sms_client'
            Arguments  = @{
                uFlags = [uint32]$uFlags
            }
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer
            $Result['PolicyReset'] = $false
            if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer'] [ResetType = '$ResetType']", "Reset CCM Policy")) {
                try {
                    $Invocation = switch ($Computer -eq $env:ComputerName) {
                        $true {
                            Invoke-CimMethod @policyResetSplat
                        }
                        $false {
                            $invokeCommandSplat = @{
                                ArgumentList = $policyResetSplat
                                ScriptBlock  = {
                                    param($policyResetSplat)
                                    Invoke-CimMethod @policyResetSplat
                                }
                            }
                            Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                        }
                    }
                    if ($Invocation) {
                        Write-Verbose "Successfully invoked policy reset on $Computer via the 'ResetPolicy' CIM method"
                        $Result['PolicyReset'] = $true
                    }
                    [pscustomobject]$Result
                }
                catch {
                    $ErrorMessage = $_.Exception.Message
                    Write-Error $ErrorMessage
                }
            }
        }
    }
}
#EndRegion '.\Public\Invoke-CCMResetPolicy.ps1' 85
#Region '.\Public\Invoke-CCMSoftwareUpdate.ps1' 0
function Invoke-CCMSoftwareUpdate {
    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'ComputerName')]
    [Alias('Invoke-CCMUpdate')]
    param(
        [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [string[]]$ArticleID,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $invokeCIMMethodSplat = @{
            Namespace  = 'root\ccm\clientsdk'
            MethodName = 'InstallUpdates'
            ClassName  = 'CCM_SoftwareUpdatesManager'
        }
        $getUpdateSplat = @{
            Namespace = 'root\CCM\ClientSDK'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer
            $Result['Invoked'] = $false

            if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer']", "Invoke-CCMUpdate")) {
                try {
                    $getUpdateSplat['Query'] = switch ($PSBoundParameters.ContainsKey('ArticleID')) {
                        $true {
                            [string]::Format('SELECT * FROM CCM_SoftwareUpdate WHERE ComplianceState = 0 AND (ArticleID = "{0}")', [string]::Join('" OR ArticleID = "', $ArticleID))
                        }
                        $false {
                            [string]::Format('SELECT * FROM CCM_SoftwareUpdate WHERE ComplianceState = 0')
                        }
                    }

                    [ciminstance[]]$MissingUpdates = switch ($Computer -eq $env:ComputerName) {
                        $true {
                            Get-CimInstance @getUpdateSplat @connectionSplat
                        }
                        $false {
                            Get-CCMCimInstance @getUpdateSplat @connectionSplat
                        }
                    }

                    if ($MissingUpdates -is [ciminstance[]]) {
                        switch ($PSBoundParameters.ContainsKey('ArticleID')) {
                            $false {
                                $ArticleID = $MissingUpdates.ArticleID
                            }
                        }
                        $invokeCIMMethodSplat['Arguments'] = @{
                            CCMUpdates = [ciminstance[]]$MissingUpdates
                        }
                    }
                    else {
                        Write-Warning "$Computer has no updates available to invoke"
                    }
                    $Invocation = switch ($Computer -eq $env:ComputerName) {
                        $true {
                            Invoke-CimMethod @invokeCIMMethodSplat
                        }
                        $false {
                            $invokeCommandSplat = @{
                                ScriptBlock  = {
                                    param($invokeCIMMethodSplat)
                                    Invoke-CimMethod @invokeCIMMethodSplat
                                }
                                ArgumentList = $invokeCIMMethodSplat
                            }
                            Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                        }
                    }
                    if ($Invocation) {
                        Write-Verbose "Successfully invoked updates on $Computer via the 'InstallUpdates' CIM method"
                        $Result['Invoked'] = $true
                    }

                }
                catch {
                    $ErrorMessage = $_.Exception.Message
                    Write-Error $ErrorMessage
                }
                [pscustomobject]$Result
            }
        }
    }
}
#EndRegion '.\Public\Invoke-CCMSoftwareUpdate.ps1' 110
#Region '.\Public\Invoke-CCMTaskSequence.ps1' 0
function Invoke-CCMTaskSequence {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [Alias('PKG_PackageID')]
        [string[]]$PackageID,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [Alias('PKG_Name')]
        [string[]]$TaskSequenceName,
        [Parameter(Mandatory = $false)]
        [switch]$Force,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    Begin {
        $setAlwaysRerunSplat = @{
            Property = @{
                ADV_RepeatRunBehavior    = 'RerunAlways'
                ADV_MandatoryAssignments = $true
            }
        }

        #region define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
        $getTaskSequenceSplat = @{
            NameSpace = 'root\CCM\Policy\Machine\ActualConfig'
        }
        #endregion define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
    }
    process {
        # temp fix for when PSComputerName from pipeline is empty - we assume it is $env:ComputerName
        switch ($PSCmdlet.ParameterSetName) {
            'ComputerName' {
                switch ([string]::IsNullOrWhiteSpace($ComputerName)) {
                    $true {
                        $ComputerName = $env:ComputerName
                    }
                }
            }
        }
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer']", "Invoke-CCMTaskSequence")) {
                try {
                    $FilterParts = switch ($PSBoundParameters.Keys) {
                        'PackageID' {
                            [string]::Format('PKG_PackageID = "{0}"', [string]::Join('" OR PRG_ProgramName = "', $PackageID))
                        }
                        'TaskSequenceName' {
                            [string]::Format('PKG_Name = "{0}"', [string]::Join('" OR PKG_Name = "', $TaskSequenceName))
                        }
                    }
                    $Filter = switch ($null -ne $FilterParts) {
                        $true {
                            [string]::Format(' WHERE {0}', [string]::Join(' OR ', $FilterParts))
                        }
                        $false {
                            ' '
                        }
                    }
                    $getTaskSequenceSplat['Query'] = [string]::Format('SELECT * FROM CCM_TaskSequence{0}', $Filter)

                    [ciminstance[]]$TaskSequences = switch ($Computer -eq $env:ComputerName) {
                        $true {
                            Get-CimInstance @getTaskSequenceSplat @connectionSplat
                        }
                        $false {
                            Get-CCMCimInstance @getTaskSequenceSplat @connectionSplat
                        }
                    }
                    if ($TaskSequences -is [Object] -and $TaskSequences.Count -gt 0) {
                        foreach ($Advertisement in $TaskSequences) {
                            switch ($Force.IsPresent) {
                                $true {
                                    Write-Verbose "Force parameter present - Setting package to always rerun"
                                    $setAlwaysRerunSplat['InputObject'] = $Advertisement
                                    switch -regex ($ConnectionInfo.ConnectionType) {
                                        '^ComputerName$|^CimSession$' {
                                            Set-CimInstance @setAlwaysRerunSplat @connectionSplat
                                        }
                                        'PSSession' {
                                            $invokeCommandSplat = @{
                                                ScriptBlock  = {
                                                    param (
                                                        $setAlwaysRerunSplat
                                                    )
                                                    Set-CimInstance @setAlwaysRerunSplat
                                                }
                                                ArgumentList = $setAlwaysRerunSplat
                                            }
                                            Invoke-Command @invokeCommandSplat @connectionSplat
                                        }
                                    }
                                }
                            }
                            $getTaskSequenceSplat['Query'] = [string]::Format("SELECT ScheduledMessageID FROM CCM_Scheduler_ScheduledMessage WHERE ScheduledMessageID LIKE '{0}%'", $Advertisement.ADV_AdvertisementID)
                            $ScheduledMessageID = switch ($Computer -eq $env:ComputerName) {
                                $true {
                                    Get-CimInstance @getTaskSequenceSplat @connectionSplat
                                }
                                $false {
                                    Get-CCMCimInstance @getTaskSequenceSplat @connectionSplat
                                }
                            }
                            if ($null -ne $ScheduledMessageID) {
                                Invoke-CCMTriggerSchedule -ScheduleID $ScheduledMessageID.ScheduledMessageID @connectionSplat
                            }
                            else {
                                Write-Warning "No ScheduledMessageID found for $Computer based on input filters"
                            }
                        }
                    }
                    else {
                        Write-Warning "No deployed task sequences found for $Computer based on input filters"
                    }
                }
                catch {
                    $ErrorMessage = $_.Exception.Message
                    Write-Error $ErrorMessage
                }
            }
        }
    }
}
#EndRegion '.\Public\Invoke-CCMTaskSequence.ps1' 147
#Region '.\Public\Invoke-CCMTriggerSchedule.ps1' 0
function Invoke-CCMTriggerSchedule {
    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'ComputerName')]
    param
    (
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [string[]]$ScheduleID,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $invokeClientActionSplat = @{
            MethodName  = 'TriggerSchedule'
            Namespace   = 'root\ccm'
            ClassName   = 'sms_client'
            ErrorAction = 'Stop'
        }
    }
    process {
        foreach ($ID in $ScheduleID) {
            foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
                $getConnectionInfoSplat = @{
                    $PSCmdlet.ParameterSetName = $Connection
                }
                switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                    $true {
                        $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                    }
                }
                $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
                $Computer = $ConnectionInfo.ComputerName
                $connectionSplat = $ConnectionInfo.connectionSplat
                $Result = [ordered]@{ }
                $Result['ComputerName'] = $Computer
                $Result['Invoked'] = $false

                if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer'] [ScheduleID = '$ID']", "Invoke ScheduleID")) {
                    try {
                        $invokeClientActionSplat['Arguments'] = @{
                            sScheduleID = $ID
                        }

                        Write-Verbose "Triggering a [ScheduleID = '$ID'] on $Computer via the 'TriggerSchedule' CIM method"
                        $Invocation = switch ($Computer -eq $env:ComputerName) {
                            $true {
                                Invoke-CimMethod @invokeClientActionSplat
                            }
                            $false {
                                $invokeCommandSplat = @{
                                    ScriptBlock  = {
                                        param($invokeClientActionSplat)
                                        Invoke-CimMethod @invokeClientActionSplat
                                    }
                                    ArgumentList = $invokeClientActionSplat
                                }
                                Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                            }
                        }
                    }
                    catch [System.UnauthorizedAccessException] {
                        Write-Error -Message "Access denied to $Computer" -Category AuthenticationError -Exception $_.Exception
                    }
                    catch {
                        Write-Warning "Failed to invoke the $ID ScheduleID via CIM. Error: $($_.Exception.Message)"
                    }
                    if ($Invocation) {
                        Write-Verbose "Successfully invoked the $ID ScheduleID on $Computer via the 'TriggerSchedule' CIM method"
                        $Result['Invoked'] = $true
                    }

                    [pscustomobject]$Result
                }
            }
        }
    }
}
#EndRegion '.\Public\Invoke-CCMTriggerSchedule.ps1' 85
#Region '.\Public\Invoke-CIMPowerShell.ps1' 0
function Invoke-CIMPowerShell {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param
    (
        [Parameter(Mandatory = $false)]
        $PipeName = ([guid]::NewGuid()).Guid.ToString(),
        [Parameter(Mandatory = $true)]
        [scriptblock]$ScriptBlock,
        [Parameter(Mandatory = $false)]
        [string[]]$FunctionsToLoad,
        [Parameter(Mandatory = $false)]
        [ValidateRange(1000, 900000)]
        [int32]$Timeout = 120000,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName
    )
    begin {
        $invokeCommandSplat = @{
            ClassName  = 'Win32_Process'
            MethodName = 'Create'
        }

        $SupportFunctions = Convert-FunctionToString -FunctionToConvert 'ConvertTo-CCMCodeStringFromObject'
        $HelperFunctions = switch ($PSBoundParameters.ContainsKey('FunctionsToLoad')) {
            $true {
                Convert-FunctionToString -FunctionToConvert $FunctionsToLoad
            }
        }

        $ScriptBlockString = [string]::Format(@'
        {0}
 
        $namedPipe = New-Object System.IO.Pipes.NamedPipeServerStream "{1}", "Out"
        $namedPipe.WaitForConnection()
        $streamWriter = New-Object System.IO.StreamWriter $namedPipe
        $streamWriter.AutoFlush = $true
        $TempResultPreConversion = & {{
            {2}
 
            {3}
        }}
        $results = ConvertTo-CCMCodeStringFromObject -inputObject $TempResultPreConversion
        $streamWriter.WriteLine("$($results)")
        $streamWriter.dispose()
        $namedPipe.dispose()
'@
 , $SupportFunctions, $PipeName, $HelperFunctions, $ScriptBlock)

        $scriptBlockPreEncoded = [scriptblock]::Create($ScriptBlockString)
        $byteCommand = [System.Text.encoding]::UTF8.GetBytes($scriptBlockPreEncoded)
        $encodedScriptBlock = [convert]::ToBase64string($byteCommand)
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly -Scope Local)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $invokeCommandSplat['Arguments'] = @{
                CommandLine = [string]::Format("powershell.exe (invoke-command ([scriptblock]::Create([system.text.encoding]::UTF8.GetString([System.convert]::FromBase64string('{0}')))))", $encodedScriptBlock)
            }

            $null = Invoke-CimMethod @invokeCommandSplat @connectionSplat

            $namedPipe = New-Object System.IO.Pipes.NamedPipeClientStream $Computer, "$($PipeName)", "In"
            $namedPipe.Connect($timeout)
            $streamReader = New-Object System.IO.StreamReader $namedPipe

            while ($null -ne ($data = $streamReader.ReadLine())) {
                $tempData = $data
            }

            $streamReader.dispose()
            $namedPipe.dispose()

            if (-not [string]::IsNullOrWhiteSpace($tempData)) {
                ConvertFrom-CCMCodeStringToObject -inputString $tempData
            }
        }
    }
}
#EndRegion '.\Public\Invoke-CIMPowerShell.ps1' 87
#Region '.\Public\New-LoopAction.ps1' 0
function New-LoopAction {
    param
    (
        [parameter(Mandatory = $true, ParameterSetName = 'DoUntil')]
        [int32]$LoopTimeout,
        [parameter(Mandatory = $true, ParameterSetName = 'DoUntil')]
        [ValidateSet('Seconds', 'Minutes', 'Hours', 'Days')]
        [string]$LoopTimeoutType,
        [parameter(Mandatory = $true)]
        [int32]$LoopDelay,
        [parameter(Mandatory = $false, ParameterSetName = 'DoUntil')]
        [ValidateSet('Milliseconds', 'Seconds', 'Minutes')]
        [string]$LoopDelayType = 'Seconds',
        [parameter(Mandatory = $true, ParameterSetName = 'ForLoop')]
        [int32]$Iterations,
        [parameter(Mandatory = $true)]
        [scriptblock]$ScriptBlock,
        [parameter(Mandatory = $true, ParameterSetName = 'DoUntil')]
        [parameter(Mandatory = $false, ParameterSetName = 'ForLoop')]
        [scriptblock]$ExitCondition,
        [parameter(Mandatory = $false)]
        [scriptblock]$IfTimeoutScript,
        [parameter(Mandatory = $false)]
        [scriptblock]$IfSucceedScript
    )
    begin {
        switch ($PSCmdlet.ParameterSetName) {
            'DoUntil' {
                $paramNewTimeSpan = @{
                    $LoopTimeoutType = $LoopTimeout
                }    
                $TimeSpan = New-TimeSpan @paramNewTimeSpan
                $StopWatch = [System.Diagnostics.Stopwatch]::StartNew()
                $FirstRunDone = $false        
            }
        }
    }
    process {
        switch ($PSCmdlet.ParameterSetName) {
            'DoUntil' {
                do {
                    switch ($FirstRunDone) {
                        $false {
                            $FirstRunDone = $true
                        }
                        Default {
                            $paramStartSleep = @{
                                $LoopDelayType = $LoopDelay
                            }
                            Start-Sleep @paramStartSleep
                        }
                    }
                    $ScriptBlock.Invoke()
                }
                until ($ExitCondition.Invoke() -or $StopWatch.Elapsed -ge $TimeSpan)
            }
            'ForLoop' {
                for ($i = 0; $i -lt $Iterations; $i++) {
                    switch ($FirstRunDone) {
                        $false {
                            $FirstRunDone = $true
                        }
                        Default {
                            $paramStartSleep = @{
                                $LoopDelayType = $LoopDelay
                            }
                            Start-Sleep @paramStartSleep
                        }
                    }
                    $ScriptBlock.Invoke()
                    if ($PSBoundParameters.ContainsKey('ExitCondition')) {
                        if ($ExitCondition.Invoke()) {
                            break
                        }
                    }
                }
            }
        }
    }
    end {
        switch ($PSCmdlet.ParameterSetName) {
            'DoUntil' {
                if ((-not $ExitCondition.Invoke()) -and $StopWatch.Elapsed -ge $TimeSpan -and $PSBoundParameters.ContainsKey('IfTimeoutScript')) {
                    $IfTimeoutScript.Invoke()
                }
                if ($ExitCondition.Invoke() -and $PSBoundParameters.ContainsKey('IfSucceedScript')) {
                    $IfSucceedScript.Invoke()
                }
                $StopWatch.Reset()
            }
            'ForLoop' {
                if ($PSBoundParameters.ContainsKey('ExitCondition')) {
                    if ((-not $ExitCondition.Invoke()) -and $i -ge $Iterations -and $PSBoundParameters.ContainsKey('IfTimeoutScript')) {
                        $IfTimeoutScript.Invoke()
                    }
                    elseif ($ExitCondition.Invoke() -and $PSBoundParameters.ContainsKey('IfSucceedScript')) {
                        $IfSucceedScript.Invoke()
                    }
                }
                else {
                    if ($i -ge $Iterations -and $PSBoundParameters.ContainsKey('IfTimeoutScript')) {
                        $IfTimeoutScript.Invoke()
                    }
                    elseif ($i -lt $Iterations -and $PSBoundParameters.ContainsKey('IfSucceedScript')) {
                        $IfSucceedScript.Invoke()
                    }
                }
            }
        }
    }
}
#EndRegion '.\Public\New-LoopAction.ps1' 112
#Region '.\Public\Remove-CCMCacheContent.ps1' 0
function Remove-CCMCacheContent {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param(
        [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [string[]]$ContentID,
        [parameter(Mandatory = $false)]
        [switch]$Clear,
        [parameter(Mandatory = $false)]
        [switch]$Force,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        switch ($PSBoundParameters.Keys -contains 'ContentID' -and $PSBoundParameters.Keys -contains 'Clear') {
            $true {
                Write-Error -ErrorAction Stop -Message 'Both ContentID and Clear parameters provided - please only provide one. Note that ParameterSetName is in use, but is currently being used for CimSession/ComputerName distinction. Feel free to make a pull request ;)'
            }
        }
        $invokeCommandSplat = @{
            FunctionsToLoad = 'Remove-CCMCacheContent', 'Get-CCMConnection'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer']", "Remove-CCMCacheContent")) {
                $removeCacheContentArgs = switch ($PSBoundParameters.Keys) {
                    'ContentID' {
                        [string]::Format('-ContentID "{0}"', [string]::Join('", "', $ContentID))
                    }
                    'Clear' {
                        '-Clear'
                    }
                    'Force' {
                        '-Force'
                    }
                }
                switch ($Computer -eq $env:ComputerName) {
                    $true {
                        $Client = New-Object -ComObject UIResource.UIResourceMGR
                        $Cache = $Client.GetCacheInfo()
                        $CacheContent = $Cache.GetCacheElements()
                        foreach ($ID in $ContentID) {
                            foreach ($CacheItem in $CacheContent) {
                                $CacheElementToRemove = switch ($PSBoundParameters.Keys) {
                                    'ContentID' {
                                        switch ($CacheItem.ContentID -eq $ID) {
                                            $true {
                                                $CacheItem.CacheElementId
                                            }
                                        }
                                    }
                                    'Clear' {
                                        $CacheItem.CacheElementId
                                    }
                                }
                                switch ($null -ne $CacheElementToRemove) {
                                    $true {
                                        switch ($Force.IsPresent) {
                                            $false {
                                                $Cache.DeleteCacheElement($CacheElementToRemove)
                                            }
                                            $true {
                                                $Cache.DeleteCacheElementEx($CacheElementToRemove, 1)
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    $false {
                        $ScriptBlock = [string]::Format('Remove-CCMCacheContent {0}', [string]::Join(' ', $removeCacheContentArgs))
                        $invokeCommandSplat['ScriptBlock'] = [scriptblock]::Create($ScriptBlock)
                        Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                    }
                }
            }
        }
    }
}
#EndRegion '.\Public\Remove-CCMCacheContent.ps1' 102
#Region '.\Public\Repair-CCMCacheLocation.ps1' 0
function Repair-CCMCacheLocation {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Return = [ordered]@{ }

            try {
                if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer']", "Repair CCM Cache Location")) {
                    $Cache = Get-CCMCacheInfo @connectionSplat
                    if ($Cache -is [pscustomobject]) {
                        $CurrentLocation = $Cache.Location
                        $NewLocation = $CurrentLocation -replace '\\\\', '\' -replace '(ccmcache\\?)+', 'ccmcache'
                        switch ($NewLocation -eq $CurrentLocation) {
                            $true {
                                $Return[$Computer] = $true
                            }
                            $false {
                                $connectionSplat['Location'] = $NewLocation
                                $SetCache = Set-CCMCacheLocation @connectionSplat
                                $Return[$Computer] = $SetCache.$Computer
                            }
                        }
                    }
                    Write-Output $Return
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Repair-CCMCacheLocation.ps1' 61
#Region '.\Public\Set-CCMCacheLocation.ps1' 0
function Set-CCMCacheLocation {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param (
        [parameter(Mandatory = $true)]
        [ValidateScript( { -not $_.EndsWith('\') } )]
        [string]$Location,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {       
        $FullCachePath = switch ($Location.EndsWith('ccmcache', 'CurrentCultureIgnoreCase')) {
            $true {
                Write-Output $Location
            }
            $false {
                Join-Path -Path $Location -ChildPath 'ccmcache'
            }
        }
        
        $GetCacheSplat = @{
            Namespace = 'root\CCM\SoftMgmtAgent'
            ClassName = 'CacheConfig'
        }
        $SetCacheScriptblock = [scriptblock]::Create([string]::Format('(New-Object -ComObject UIResource.UIResourceMgr).GetCacheInfo().Location = "{0}"', (Split-Path -Path $FullCachePath -Parent)))
        $SetCacheSplat = @{
            ScriptBlock = $SetCacheScriptblock
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Return = [ordered]@{ }

            try {
                if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer'] [Location = '$Location']", "Set CCM Cache Location")) {
                    $Cache = switch ($Computer -eq $env:ComputerName) {
                        $true {
                            Get-CimInstance @GetCacheSplat @connectionSplat
                        }
                        $false {
                            Get-CCMCimInstance @GetCacheSplat @connectionSplat
                        }
                    }
                    if ($Cache -is [object]) {
                        switch ($Cache.Location) {
                            $FullCachePath {
                                $Return[$Computer] = $true
                            }
                            default {
                                switch ($Computer -eq $env:ComputerName) {
                                    $true {
                                        $SetCacheScriptblock.Invoke()
                                    }
                                    $false {
                                        Invoke-CCMCommand @SetCacheSplat @connectionSplat
                                    }
                                }
                                $Cache = switch ($Computer -eq $env:ComputerName) {
                                    $true {
                                        Get-CimInstance @GetCacheSplat @connectionSplat
                                    }
                                    $false {
                                        Get-CCMCimInstance @GetCacheSplat @connectionSplat
                                    }
                                }
                                switch ($Cache.Location) {
                                    $FullCachePath {
                                        $Return[$Computer] = $true
                                    }
                                    default {       
                                        $Return[$Computer] = $false
                                    }
                                }
                            }
                        }
                    }
                    Write-Output $Return
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Set-CCMCacheLocation.ps1' 107
#Region '.\Public\Set-CCMCacheSize.ps1' 0
function Set-CCMCacheSize {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param (
        [parameter(Mandatory = $true)]
        [ValidateRange(1, 99999)]
        [int]$Size,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $GetCacheSplat = @{
            Namespace   = 'root\CCM\SoftMgmtAgent'
            ClassName   = 'CacheConfig'
            ErrorAction = 'Stop'
        }
        $SetCacheSizeScriptBlockString = [string]::Format('(New-Object -ComObject UIResource.UIResourceMgr).GetCacheInfo().TotalSize = {0}', $Size)
        $SetCacheSizeScriptBlock = [scriptblock]::Create($SetCacheSizeScriptBlockString)
        $invokeCommandSplat = @{
            ScriptBlock = $SetCacheSizeScriptBlock
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Return = [ordered]@{ }

            try {
                if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer'] [Size = '$Size']", "Set CCM Cache Size")) {
                    $Cache = switch ($Computer -eq $env:ComputerName) {
                        $true {
                            Get-CimInstance @GetCacheSplat @connectionSplat
                        }
                        $false {
                            Get-CCMCimInstance @GetCacheSplat @connectionSplat
                        }
                    }
                    if ($Cache -is [object]) {
                        switch ($Cache.Size) {
                            $Size {
                                $Return[$Computer] = $true
                            }
                            default {
                                switch ($Computer -eq $env:ComputerName) {
                                    $true {
                                        $SetCacheSizeScriptBlock.Invoke()
                                    }
                                    $false {
                                        Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                                    }
                                }
                                $Cache = switch ($Computer -eq $env:ComputerName) {
                                    $true {
                                        Get-CimInstance @GetCacheSplat @connectionSplat
                                    }
                                    $false {
                                        Get-CCMCimInstance @GetCacheSplat @connectionSplat
                                    }
                                }
                                if ($Cache -is [Object] -and $Cache.Size -eq $Size) {
                                    $Return[$Computer] = $true
                                }
                                else {
                                    $Return[$Computer] = $false
                                }
                            }
                        }
                    }
                    Write-Output $Return
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Set-CCMCacheSize.ps1' 98
#Region '.\Public\Set-CCMClientAlwaysOnInternet.ps1' 0
function Set-CCMClientAlwaysOnInternet {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateSet('Enabled', 'Disabled')]
        [string]$Status,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $Enablement = switch ($Status) {
            'Enabled' {
                1
            }
            'Disabled' {
                0
            }
        }
        $SetAlwaysOnInternetSplat = @{
            Force        = $true
            PropertyType = 'DWORD'
            Property     = 'ClientAlwaysOnInternet'
            Value        = $Enablement
            Key          = 'SOFTWARE\Microsoft\CCM\Security'
            RegRoot      = 'HKEY_LOCAL_MACHINE'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            try {
                Set-CCMRegistryProperty @SetAlwaysOnInternetSplat @connectionSplat
            }
            catch {
                Write-Error "Failure to set MEMCM ClientAlwaysOnInternet to $Enablement for $Computer - $($_.Exception.Message)"
            }
        }
    }
}
#EndRegion '.\Public\Set-CCMClientAlwaysOnInternet.ps1' 60
#Region '.\Public\Set-CCMDNSSuffix.ps1' 0
function Set-CCMDNSSuffix {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param(
        [parameter(Mandatory = $false)]
        [string]$DNSSuffix,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $SetDNSSuffixScriptBlockString = [string]::Format('(New-Object -ComObject Microsoft.SMS.Client).SetDNSSuffix("{0}")', $DNSSuffix)
        $SetDNSSuffixScriptBlock = [scriptblock]::Create($SetDNSSuffixScriptBlockString)
        $invokeCommandSplat = @{
            ScriptBlock = $SetDNSSuffixScriptBlock
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer
            if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer'] [DNSSuffix = '$DNSSuffix']", "Set-CCMDNSSuffix")) {
                try {
                    switch ($Computer -eq $env:ComputerName) {
                        $true {
                            $SetDNSSuffixScriptBlock.Invoke()
                        }
                        $false {
                            Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                        }
                    }
                    $Result['DNSSuffixSet'] = $true
                }
                catch {
                    $Result['DNSSuffixSet'] = $false
                    Write-Error "Failure to set DNS Suffix to $DNSSuffix for $Computer - $($_.Exception.Message)"
                }
                [pscustomobject]$Result
            }
        }
    }
}
#EndRegion '.\Public\Set-CCMDNSSuffix.ps1' 62
#Region '.\Public\Set-CCMLoggingConfiguration.ps1' 0
function Set-CCMLoggingConfiguration {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param (
        [Parameter(Mandatory = $false)]
        [ValidateSet('Default', 'Verbose', 'None')]
        [string]$LogLevel,
        [Parameter(Mandatory = $false)]
        [int]$LogMaxSize,
        [Parameter(Mandatory = $false)]
        [int]$LogMaxHistory,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $BaseLogConfigSplat = @{
            Force        = $true
            PropertyType = 'String'
            Key          = 'SOFTWARE\Microsoft\CCM\Logging\@Global'
            RegRoot      = 'HKEY_LOCAL_MACHINE'
        }

        #region Format some parameters if provided
        switch ($PSBoundParameters.Keys) {
            '^LogDirectory$' {
                $LogDirectory = $LogDirectory.TrimEnd('\')
            }
            '^LogLevel$' {
                $LogLevel = switch ($LogLevel) {
                    'None' {
                        2
                    }
                    'Default' {
                        1
                    }
                    'Verbose' {
                        0
                    }
                }
            }
        }
        #endregion Format some parameters if provided
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            if ($PSCmdlet.ShouldProcess([string]::Join(' ', $PSBoundParameters.Keys), "Set-CCMLoggingConfiguration")) {
                $Result = [ordered]@{ }
                $Result['ComputerName'] = $Computer
                $Result['LogConfigChanged'] = $false

                try {
                    switch -regex ($PSBoundParameters.Keys) {
                        "^LogDirectory$|^LogLevel$|^LogMaxSize$|^LogMaxHistory$" { 
                            $BaseLogConfigSplat['Property'] = $PSItem
                            $BaseLogConfigSplat['Value'] = Get-Variable -Name $PSItem -ValueOnly -Scope Local
                            Set-CCMRegistryProperty @BaseLogConfigSplat @connectionSplat
                        }
                    }
                    Write-Warning "The CCMExec service needs restarted for log location changes to take full affect."
                    $Result['LogConfigChanged'] = $true
                }
                catch {
                    $ErrorMessage = $_.Exception.Message
                    Write-Error $ErrorMessage
                    [pscustomobject]$Result
                }
                [pscustomobject]$Result
            }
        }
    }
}
#EndRegion '.\Public\Set-CCMLoggingConfiguration.ps1' 92
#Region '.\Public\Set-CCMManagementPoint.ps1' 0
function Set-CCMManagementPoint {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    [Alias('Set-CCMMP')]
    param(
        [parameter(Mandatory = $true)]
        [string]$ManagementPointFQDN,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $SetCurrentManagementPointScriptBlockString = [string]::Format('(New-Object -ComObject Microsoft.SMS.Client).SetCurrentManagementPoint("{0}", 1)', $ManagementPointFQDN)
        $SetCurrentManagementPointScriptBlock = [scriptblock]::Create($SetCurrentManagementPointScriptBlockString)
        $invokeCommandSplat = @{
            ScriptBlock = $SetCurrentManagementPointScriptBlock
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer
            $Result['ManagementPointFQDNSet'] = $false

            if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer'] [ManagementPointFQDN = '$ManagementPointFQDN']", "Set-CCMManagementPoint")) {
                try {
                    switch ($Computer -eq $env:ComputerName) {
                        $true {
                            $SetCurrentManagementPointScriptBlock.Invoke()
                        }
                        $false {
                            Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                        }
                    }
                    $Result['ManagementPointFQDNSet'] = $true
                }
                catch {
                    Write-Error "Failure to set management point to $ManagementPointFQDN for $Computer - $($_.Exception.Message)"
                }
                [pscustomobject]$Result
            }
        }
    }
}
#EndRegion '.\Public\Set-CCMManagementPoint.ps1' 64
#Region '.\Public\Set-CCMProvisioningMode.ps1' 0
function Set-CCMProvisioningMode {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param (
        [parameter(Mandatory = $false)]
        [ValidateSet('Enabled', 'Disabled')]
        [string]$Status,
        [parameter(Mandatory = $false)]
        [ValidateRange(60, [int]::MaxValue)]
        [int]$ProvisioningMaxMinutes,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        [bool]$ProvisioningMode = switch ($Status) {
            'Enabled' {
                $true
            }
            'Disabled' {
                $false
            }
        }
        $SetProvisioningModeSplat = @{
            Namespace  = 'root\CCM'
            ClassName  = 'SMS_Client'
            MethodName = 'SetClientProvisioningMode'
            Arguments  = @{
                bEnable = $ProvisioningMode
            }
        }
        $setCIMRegistryPropertySplat = @{
            RegRoot      = 'HKEY_LOCAL_MACHINE'
            Key          = 'Software\Microsoft\CCM\CcmExec'
            Property     = 'ProvisioningMaxMinutes'
            Value        = $ProvisioningMaxMinutes
            PropertyType = 'DWORD'
            Force        = $true
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Return = [ordered]@{ }
            $Return['ComputerName'] = $Computer
            $Return['ProvisioningModeChanged'] = $false
            $Return['ProvisioningMaxMinutesChanged'] = $false
            try {
                if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer'] [ProvisioningMode = '$Status'] [ProvisioningMaxMinutes = '$ProvisioningMaxMinutes']", "Set CCM Provisioning Mode")) {
                    switch ($PSBoundParameters.Keys) {
                        'Status' {
                            $Invocation = switch ($Computer -eq $env:ComputerName) {
                                $true {
                                    Invoke-CimMethod @SetProvisioningModeSplat
                                }
                                $false {
                                    $invokeCommandSplat = @{
                                        ArgumentList = $SetProvisioningModeSplat
                                        ScriptBlock  = {
                                            param($StatuSetProvisioningModeSplats)
                                            Invoke-CimMethod @SetProvisioningModeSplat
                                        }
                                    }
                                    Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                                }
                            }
                            if ($Invocation) {
                                Write-Verbose "Successfully set provisioning mode to $Status for $Computer via the 'SetClientProvisioningMode' CIM method"
                                $Return['ProvisioningModeChanged'] = $true
                            }
                        }
                        'ProvisioningMaxMinutes' {
                            $MaxMinutesChange = Set-CCMRegistryProperty @setCIMRegistryPropertySplat @connectionSplat
                            if ($MaxMinutesChange[$Computer]) {
                                Write-Verbose "Successfully set ProvisioningMaxMinutes for $Computer to $ProvisioningMaxMinutes"
                                $Return['ProvisioningMaxMinutesChanged'] = $true
                            }
                        }
                    }
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
            [pscustomobject]$Return
        }
    }
}
#EndRegion '.\Public\Set-CCMProvisioningMode.ps1' 108
#Region '.\Public\Set-CCMRegistryProperty.ps1' 0
function Set-CCMRegistryProperty {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    [Alias('Set-CIMRegistryProperty')]
    param (
        [parameter(Mandatory = $true)]
        [ValidateSet('HKEY_LOCAL_MACHINE', 'HKEY_USERS', 'HKEY_CURRENT_CONFIG', 'HKEY_DYN_DATA', 'HKEY_CLASSES_ROOT', 'HKEY_CURRENT_USER')]
        [string]$RegRoot,
        [parameter(Mandatory = $true)]
        [string]$Key,
        [parameter(Mandatory = $true)]
        [string]$Property,
        [parameter(Mandatory = $true)]
        $Value,
        [parameter(Mandatory = $true)]
        [ValidateSet('String', 'ExpandedString', 'Binary', 'DWORD', 'MultiString', 'QWORD')]
        [string]$PropertyType,
        [parameter(Mandatory = $false)]
        [switch]$Force,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region create hash tables for translating values
        $RootKey = @{
            HKEY_CLASSES_ROOT   = 2147483648
            HKEY_CURRENT_USER   = 2147483649
            HKEY_LOCAL_MACHINE  = 2147483650
            HKEY_USERS          = 2147483651
            HKEY_CURRENT_CONFIG = 2147483653
            HKEY_DYN_DATA       = 2147483654
        }
        <#
            Maps the 'PropertyType' per property to the method we will invoke to set the value.
            For example, if the 'type' is string we have invoke the SetStringValue method
        #>

        $RegPropertyMethod = @{
            'String'         = 'SetStringValue'
            'ExpandedString' = 'SetExpandedStringValue'
            'Binary'         = 'SetBinaryValue'
            'DWORD'          = 'SetDWORDValue'
            'MultiString'    = 'SetMultiStringValue'
            'QWORD'          = 'SetQWORDValue'
        }
        $Method = $RegPropertyMethod[$PropertyType]
        #endregion create hash tables for translating values

        # convert RootKey friendly name to the [uint32] equivalent so it can be used later
        $Root = $RootKey[$RegRoot]

        #region define our hash tables for parameters to pass to Get-CIMInstance and our return hash table
        $setCIMRegPropSplat = @{
            Namespace   = 'root\default'
            ClassName   = 'StdRegProv'
            ErrorAction = 'Stop'
        }
        #endregion define our hash tables for parameters to pass to Get-CIMInstance and our return hash table

        $PropertyTypeMap = @{
            SetDWORDValue          = [UInt32]
            SetQWORDValue          = [UInt64]
            SetStringValue         = [String]
            SetMultiStringValue    = [String[]]
            SetExpandedStringValue = [String]
            SetBinaryValue         = [byte[]]
        }

        $ReturnValName = @{
            SetDWORDValue          = 'uValue'
            SetQWORDValue          = 'uValue'
            SetStringValue         = 'sValue'
            SetMultiStringValue    = 'sValue'
            SetExpandedStringValue = 'sValue'
            SetBinaryValue         = 'uValue'
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Return = [ordered]@{ }
            $Return[$Computer] = $false

            if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer'] [sValueName = '$Property'] [Value = '$Value']", "Set-CCMRegistryProperty")) {
                switch -regex ($ConnectionInfo.ConnectionType) {
                    '^CimSession$|^ComputerName$' {
                        $setCIMRegPropSplat['MethodName'] = 'EnumValues'
                        $setCIMRegPropSplat['Arguments'] = @{
                            hDefKey     = [uint32]$Root
                            sSubKeyName = $Key
                        }

                        $EnumValues = Invoke-CimMethod @setCIMRegPropSplat @connectionSplat

                        $setCIMRegPropSplat['MethodName'] = $Method
                        $setCIMRegPropSplat['Arguments']['sValueName'] = $Property
                        $setCIMRegPropSplat['Arguments'][$ReturnValName[$Method]] = $Value -as $PropertyTypeMap[$Method]

                        switch ($EnumValues.sNames -contains $Property) {
                            $true {
                                $SetProperty = Invoke-CimMethod @setCIMRegPropSplat @connectionSplat
                            }
                            $false {
                                switch ($Force.IsPresent) {
                                    $true {
                                        $SetProperty = Invoke-CimMethod @setCIMRegPropSplat @connectionSplat
                                    }
                                    $false {
                                        Write-Warning ([string]::Format('[Property = {0}] does not exist under [Key = {1}\{2}] and the force parameter was not specified. No changes will be made', $Property, $RegRoot, $Key))
                                    }
                                }
                            }
                        }
                        if ($null -ne $SetProperty) {
                            switch ($SetProperty.ReturnValue) {
                                0 {
                                    $Return[$Computer] = $true
                                }
                                default {
                                    Write-Error ([string]::Format('Failed to set value [Property = {0}] [Key = {1}\{2}] [Value = {3}] [PropertyType = {4}] [Method = {5}]', $Property, $RegRoot, $Key, $Value, $PropertyType, $Method))
                                }
                            }
                        }
                    }
                    '^PSSession$' {
                        $RegPath = [string]::Format('registry::{0}\{1}', $RegRoot, $Key)
                        $InvokeCommandSplat = @{
                            ArgumentList = $RegPath, $Property, $Value, $PropertyType, $Force.IsPresent
                        }

                        $InvokeCommandSplat['ScriptBlock'] = {
                            param(
                                $RegPath,
                                $Property,
                                $Value,
                                $PropertyType,
                                $Force
                            )
                            $Exists = Get-ItemProperty -Path $RegPath -Name $Property -ErrorAction SilentlyContinue
                            try {
                                switch ([bool]$Exists) {
                                    $true {
                                        Set-ItemProperty -Path $RegPath -Name $Property -Value $Value -Type $PropertyType -ErrorAction Stop
                                        Write-Output $true
                                    }
                                    $false {
                                        switch ([bool]$Force) {
                                            $true {
                                                Set-ItemProperty -Path $RegPath -Name $Property -Value $Value -Type $PropertyType -ErrorAction Stop
                                                Write-Output $true
                                            }
                                            $false {
                                                Write-Warning ([string]::Format('[Property = {{0}}] does not exist under [Key = {{1}}] and the force parameter was not specified. No changes will be made', $Property, $RegPath))
                                                Write-Output $false
                                            }
                                        }
                                    }
                                }
                            }
                            catch {
                                Write-Error $_.Exception.Message
                                Write-Output $false
                            }
                        }
                        
                        $Return[$Computer] = Invoke-CCMCommand @InvokeCommandSplat @connectionSplat
                    }
                }

                Write-Output $Return
            }
        }
    }
}
#EndRegion '.\Public\Set-CCMRegistryProperty.ps1' 193
#Region '.\Public\Set-CCMSite.ps1' 0
function Set-CCMSite {
    [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ComputerName')]
    param(
        [parameter(Mandatory = $true)]
        [string]$SiteCode,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $SetAssignedSiteCodeScriptBlockString = [string]::Format('(New-Object -ComObject Microsoft.SMS.Client).SetAssignedSite("{0}", 0)', $SiteCode)
        $SetAssignedSiteCodeScriptBlock = [scriptblock]::Create($SetAssignedSiteCodeScriptBlockString)
        $invokeCommandSplat = @{
            ScriptBlock = $SetAssignedSiteCodeScriptBlock
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            if ($PSCmdlet.ShouldProcess("[ComputerName = '$Computer'] [Site = '$SiteCode']", "Set-CCMSite")) {
                try {
                    switch ($Computer -eq $env:ComputerName) {
                        $true {
                            $SetAssignedSiteCodeScriptBlock.Invoke()
                            $Result['SiteSet'] = $true
                            [pscustomobject]$Result
                        }
                        $false {
                            Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                        }
                    }
                }
                catch {
                    $Result['SiteSet'] = $false
                    Write-Error "Failure to set MEMCM Site to $SiteCode for $Computer - $($_.Exception.Message)"
                }
            }
        }
    }
}
#EndRegion '.\Public\Set-CCMSite.ps1' 63
#Region '.\Public\Test-CCMIsClientAlwaysOnInternet.ps1' 0
function Test-CCMIsClientAlwaysOnInternet {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param(
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $IsClientAlwaysOnInternetScriptBlock = {
            $Client = New-Object -ComObject Microsoft.SMS.Client
            [bool]$Client.IsClientAlwaysOnInternet()
        }
        $invokeCommandSplat = @{
            ScriptBlock = $IsClientAlwaysOnInternetScriptBlock
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                switch ($Computer -eq $env:ComputerName) {
                    $true {
                        $Result['IsClientAlwaysOnInternet'] = $IsClientAlwaysOnInternetScriptBlock.Invoke()
                    }
                    $false {
                        $Result['IsClientAlwaysOnInternet'] = Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                    }
                }
                [pscustomobject]$Result
            }
            catch {
                Write-Error "Failure to determine if the MEMCM client is set to always be on the internet for $Computer - $($_.Exception.Message)"
            }
        }
    }
}
#EndRegion '.\Public\Test-CCMIsClientAlwaysOnInternet.ps1' 59
#Region '.\Public\Test-CCMIsClientOnInternet.ps1' 0
function Test-CCMIsClientOnInternet {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param(
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $IsClientOnInternetScriptBlock = {
            $Client = New-Object -ComObject Microsoft.SMS.Client
            [bool]$Client.IsClientOnInternet()
        }
        $invokeCommandSplat = @{
            ScriptBlock = $IsClientOnInternetScriptBlock
        }
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                switch ($Computer -eq $env:ComputerName) {
                    $true {
                        $Result['IsClientOnInternet'] = $IsClientOnInternetScriptBlock.Invoke()
                    }
                    $false {
                        $Result['IsClientOnInternet'] = Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                    }
                }
                [pscustomobject]$Result
            }
            catch {
                Write-Error "Failure to determine if the MEMCM client is set to always be on the internet for $Computer - $($_.Exception.Message)"
            }
        }
    }
}
#EndRegion '.\Public\Test-CCMIsClientOnInternet.ps1' 59
#Region '.\Public\Test-CCMIsWindowAvailableNow.ps1' 0
function Test-CCMIsWindowAvailableNow {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param (
        [parameter(Mandatory = $false)]
        [ValidateSet('All Deployment Service Window',
            'Program Service Window',
            'Reboot Required Service Window',
            'Software Update Service Window',
            'Task Sequences Service Window',
            'Corresponds to non-working hours')]
        [string[]]$MWType = 'Software Update Service Window',
        [Parameter(Mandatory = $false)]
        [int]$MaxRuntime,
        [Parameter(Mandatory = $false)]
        [bool]$FallbackToAllProgramsWindow,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        #region Create hashtable for mapping MW types
        $MW_Type = @{
            'All Deployment Service Window'    = 1
            'Program Service Window'           = 2
            'Reboot Required Service Window'   = 3
            'Software Update Service Window'   = 4
            'Task Sequences Service Window'    = 5
            'Corresponds to non-working hours' = 6
        }
        #endregion Create hashtable for mapping MW types

        $testInMWSplat = @{
            Namespace  = 'root\CCM\ClientSDK'
            ClassName  = 'CCM_ServiceWindowManager'
            MethodName = 'IsWindowAvailableNow'
            Arguments  = @{
                MaxRuntime = [uint32]$MaxRuntime
            }
        }
        $getCurrentWindowTimeLeft = @{
            Namespace  = 'root\CCM\ClientSDK'
            ClassName  = 'CCM_ServiceWindowManager'
            MethodName = 'GetCurrentWindowAvailableTime'
            Arguments  = @{ }
        }
        $getUpdateMWExistenceSplat = @{
            Namespace = 'root\CCM\ClientSDK'
            Query     = 'SELECT Duration FROM CCM_ServiceWindow WHERE Type = 4'
        }
        $getSoftwareUpdateFallbackSettingsSplat = @{
            Namespace = 'root\CCM\Policy\Machine\ActualConfig'
            Query     = 'SELECT ServiceWindowManagement FROM CCM_SoftwareUpdatesClientConfig'
        }
        $invokeCommandSplat = @{
            FunctionsToLoad = 'Test-CCMIsWindowAvailableNow', 'Get-CCMConnection'
        }

        $StringArgs = @(switch ($PSBoundParameters.Keys) {
                'MaxRuntime' {
                    [string]::Format('-MaxRuntime {0}', $MaxRuntime)
                }
                'FallbackToAllProgramsWindow' {
                    [string]::Format('-FallbackToAllProgramsWindow ${0}', $FallbackToAllProgramsWindow)
                }
            })
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat
            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer

            try {
                switch ($Computer -eq $env:ComputerName) {
                    $true {
                        $HasUpdateMW = $null -ne (Get-CimInstance @getUpdateMWExistenceSplat @connectionSplat).Duration
                        $FallbackSetting = (Get-CimInstance @getSoftwareUpdateFallbackSettingsSplat @connectionSplat).ServiceWindowManagement

                        foreach ($MW in $MWType) {
                            $MWFallback = switch ($FallbackToAllProgramsWindow) {
                                $true {
                                    switch ($MWType) {
                                        'Software Update Service Window' {
                                            switch ($FallbackSetting -ne $FallbackToAllProgramsWindow) {
                                                $true {
                                                    Write-Warning 'Requested fallback setting does not match the computers fallback setting for software updates'
                                                }
                                            }
                                            switch ($HasUpdateMW) {
                                                $true {
                                                    $FallbackSetting -and $HasUpdateMW
                                                }
                                                $false {
                                                    $true
                                                }
                                            }
                                        }
                                        default {
                                            $FallbackToAllProgramsWindow
                                        }
                                    }
                                }
                                $false {
                                    switch ($MWType) {
                                        'Software Update Service Window' {
                                            switch ($HasUpdateMW) {
                                                $true {
                                                    $FallbackSetting -and $HasUpdateMW
                                                }
                                                $false {
                                                    $true
                                                }
                                            }
                                        }
                                        default {
                                            $false
                                        }
                                    }
                                }
                            }
                            $testInMWSplat['Arguments']['FallbackToAllProgramsWindow'] = [bool]$MWFallback
                            $testInMWSplat['Arguments']['ServiceWindowType'] = [uint32]$MW_Type[$MW]
                            $CanProgramRunNow = Invoke-CimMethod @testInMWSplat @connectionSplat
                            if ($CanProgramRunNow -is [Object]) {
                                $getCurrentWindowTimeLeft['Arguments']['FallbackToAllProgramsWindow'] = [bool]$MWFallback
                                $getCurrentWindowTimeLeft['Arguments']['ServiceWindowType'] = [uint32]$MW_Type[$MW]
                                $TimeLeft = Invoke-CimMethod @getCurrentWindowTimeLeft @connectionSplat
                                $TimeLeftTimeSpan = New-TimeSpan -Seconds $TimeLeft.WindowAvailableTime
                                $Result['MaintenanceWindowType'] = $MW
                                $Result['CanProgramRunNow'] = $CanProgramRunNow.CanProgramRunNow
                                $Result['FallbackToAllProgramsWindow'] = $MWFallback
                                $Result['MaxRunTime'] = $MaxRuntime
                                $Result['WindowAvailableTime'] = Get-StringFromTimespan -Timespan $TimeLeftTimeSpan
                                [pscustomobject]$Result
                            }
                        }
                    }
                    $false {
                        $ScriptBlock = [string]::Format('Test-CCMIsWindowAvailableNow {0} {1}', [string]::Join(' ', $StringArgs), [string]::Format("-MWType '{0}'", [string]::Join("', '", $MWType)))
                        $invokeCommandSplat['ScriptBlock'] = [scriptblock]::Create($ScriptBlock)
                        Invoke-CCMCommand @invokeCommandSplat @connectionSplat
                    }
                }
            }
            catch {
                $ErrorMessage = $_.Exception.Message
                Write-Error $ErrorMessage
            }
        }
    }
}
#EndRegion '.\Public\Test-CCMIsWindowAvailableNow.ps1' 170
#Region '.\Public\Test-CCMStaleLog.ps1' 0
Function Test-CCMStaleLog {
    [CmdletBinding(DefaultParameterSetName = 'ComputerName')]
    param
    (
        [Parameter(Mandatory = $true)]
        [string]$LogFileName,
        [Parameter(Mandatory = $false)]
        [int]$DaysStale,
        [Parameter(Mandatory = $false)]
        [int]$HoursStale,
        [Parameter(Mandatory = $false)]
        [int]$MinutesStale,
        [Parameter(Mandatory = $false)]
        [switch]$DisableCCMSetupFallback,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'CimSession')]
        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ComputerName')]
        [Alias('Connection', 'PSComputerName', 'PSConnectionName', 'IPAddress', 'ServerName', 'HostName', 'DNSHostName')]
        [string[]]$ComputerName = $env:ComputerName,
        [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')]
        [Alias('Session')]      
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession,
        [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')]
        [ValidateSet('CimSession', 'PSSession')]
        [string]$ConnectionPreference
    )
    begin {
        $getRequestedLogInfoSplat = @{ }

        $TimeSpanSplat = @{ }
        switch ($PSBoundParameters.Keys) {
            'DaysStale' {
                $TimeSpanSplat['Days'] = $DaysStale
            }
            'HoursStale' {
                $TimeSpanSplat['Hours'] = $HoursStale
            }
            'MinutesStale' {
                $TimeSpanSplat['Minutes'] = $MinutesStale
            }
        }
        $StaleTimeframe = New-TimeSpan @TimeSpanSplat

        switch ($LogFileName.EndsWith('.log')) {
            $false {
                $LogFileName = [string]::Format('{0}.log', $LogFileName)
            }
        }

        $MEMCMClientInstallLog = "$env:windir\ccmsetup\Logs\ccmsetup.log"
    }
    process {
        foreach ($Connection in (Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)) {
            $getConnectionInfoSplat = @{
                $PSCmdlet.ParameterSetName = $Connection
            }
            switch ($PSBoundParameters.ContainsKey('ConnectionPreference')) {
                $true {
                    $getConnectionInfoSplat['Prefer'] = $ConnectionPreference
                }
            }
            $ConnectionInfo = Get-CCMConnection @getConnectionInfoSplat
            $Computer = $ConnectionInfo.ComputerName
            $connectionSplat = $ConnectionInfo.connectionSplat

            $Result = [ordered]@{ }
            $Result['ComputerName'] = $Computer
            $Result['LogFileName'] = $LogFileName
            $Result['LogLastWriteTime'] = $null
            $Result['LogStale'] = $null
            $Result['CCMSetupLastWriteTime'] = $null
            $CCMLogDirectory = (Get-CCMLoggingConfiguration @connectionSplat).LogDirectory
            $LogFullPath = [string]::Join('\', $CCMLogDirectory, $LogFileName)

            Write-Verbose $([string]::Format('Checking {0} for activity', $LogFullPath))

            $getRequestedLogInfoSplat['Query'] = [string]::Format('SELECT Readable, LastModified FROM CIM_DataFile WHERE Name = "{0}" OR Name = "{1}"', ($LogFullPath -replace "\\", "\\"), ($MEMCMClientInstallLog -replace "\\", "\\"))
            # 'Poke' the log by querying it once. Log files sometimes do not show an accurate LastModified time until they are accessed
            $null = switch ($Computer -eq $env:ComputerName) {
                $true {
                    Get-CimInstance @getRequestedLogInfoSplat @connectionSplat
                }
                $false {
                    Get-CCMCimInstance @getRequestedLogInfoSplat @connectionSplat
                }
            }
            $RequestedLogInfo = switch ($Computer -eq $env:ComputerName) {
                $true {
                    Get-CimInstance @getRequestedLogInfoSplat @connectionSplat
                }
                $false {
                    Get-CCMCimInstance @getRequestedLogInfoSplat @connectionSplat
                }
            }
            $RequestedLog = $RequestedLogInfo.Where({ $_.Name -eq $LogFullPath})
            $MEMCMSetupLog = $RequestedLogInfo.Where({ $_.Name -eq $MEMCMClientInstallLog})
            if ($null -ne $MEMCMSetupLog) {
                $Result['CCMSetupLastWriteTime'] = ([datetime]$dtmMEMCMClientInstallLogDate = $MEMCMSetupLog.LastModified)
            }
            if ($null -ne $RequestedLog) {
                $Result['LogLastWriteTime'] = ([datetime]$LogLastWriteTime = $RequestedLog.LastModified)
                $LastWriteDiff = New-TimeSpan -Start $LogLastWriteTime -End (Get-Date -format yyyy-MM-dd)
                if ($LastWriteDiff -gt $StaleTimeframe) {
                    Write-Verbose $([string]::Format('{0} is not active', $LogFullPath))
                    Write-Verbose $([string]::Format('{0} last date modified is {1}', $LogFullPath, $LogDate))
                    Write-Verbose $([string]::Format("Current Date and Time is {0}", (Get-Date)))
                    $LogStale = $true
                }
                else {
                    Write-Verbose $([string]::Format('{0}.log is active', $LogFullPath))
                    $LogStale = $false
                }
            }
            elseif (-not $DisableCCMSetupFallback.IsPresent) {
                Write-Warning $([string]::Format('{0} not found; checking for recent ccmsetup activity', $LogFullPath))
                if ($null -ne $MEMCMClientInstallLogInfo) {
                    [int]$ClientInstallHours = (New-TimeSpan -Start $dtmMEMCMClientInstallLogDate -End (Get-Date)).TotalHours
                    if ($ClientInstallHours -lt 24) {
                        Write-Warning 'CCMSetup activity detected within last 24 hours - marking log as not stale'
                        $LogStale = $false
                    }
                    else {
                        Write-Warning 'CCMSetup activity not detected within last 24 hours - marking log as stale'
                        $LogStale = $true
                    }
                }
                else {
                    Write-Warning $([string]::Format('CCMSetup.log not found in {0} - marking log as stale', $MEMCMClientInstallLog))
                    $LogStale = $true
                }
            }
            else {
                Write-Warning $([string]::Format('{0} not found', $LogFullPath))
                $LogStale = 'File Not Found'
            }
            $Result['LogStale'] = $LogStale
            [pscustomobject]$Result
        }
    }
}
#EndRegion '.\Public\Test-CCMStaleLog.ps1' 141
#Region '.\Public\Write-CCMLogEntry.ps1' 0
Function Write-CCMLogEntry {
    param (
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('Message', 'ToLog')]
        [string[]]$Value,
        [parameter(Mandatory = $false)]
        [ValidateSet('Informational', 'Warning', 'Error', '1', '2', '3')]
        [string]$Severity = 'Informational',
        [parameter(Mandatory = $false)]
        [string]$Component,
        [parameter(Mandatory = $true)]
        [string]$FileName,
        [parameter(Mandatory = $true)]
        [string]$Folder,
        [parameter(Mandatory = $false)]
        [int]$Bias = (Get-CimInstance -Query "SELECT Bias FROM Win32_TimeZone").Bias,
        [parameter(Mandatory = $false)]
        [int]$MaxLogFileSize = 5MB,
        [parameter(Mandatory = $false)]
        [int]$LogsToKeep = 0
    )
    begin {
        # Convert Severity to integer log level
        [int]$LogLevel = switch ($Severity) {
            Informational {
                1
            }
            Warning {
                2
            }
            Error {
                3
            }
            default {
                $PSItem
            }
        }

        # Determine log file location
        $LogFilePath = Join-Path -Path $Folder -ChildPath $FileName

        #region log rollover check if $MaxLogFileSize is greater than 0
        switch (([System.IO.FileInfo]$LogFilePath).Exists -and $MaxLogFileSize -gt 0) {
            $true {
                #region rename current file if $MaxLogFileSize exceeded, respecting $LogsToKeep
                switch (([System.IO.FileInfo]$LogFilePath).Length -ge $MaxLogFileSize) {
                    $true {
                        # Get log file name without extension
                        $LogFileNameWithoutExt = $FileName -replace ([System.IO.Path]::GetExtension($FileName))

                        # Get already rolled over logs
                        $AllLogs = Get-ChildItem -Path $Folder -Name "$($LogFileNameWithoutExt)_*" -File

                        # Sort them numerically (so the oldest is first in the list)
                        $AllLogs = Sort-Object -InputObject $AllLogs -Descending -Property { $_ -replace '_\d+\.lo_$' }, { [int]($_ -replace '^.+\d_|\.lo_$') } -ErrorAction Ignore

                        foreach ($Log in $AllLogs) {
                            # Get log number
                            $LogFileNumber = [int][Regex]::Matches($Log, "_([0-9]+)\.lo_$").Groups[1].Value
                            switch (($LogFileNumber -eq $LogsToKeep) -and ($LogsToKeep -ne 0)) {
                                $true {
                                    # Delete log if it breaches $LogsToKeep parameter value
                                    [System.IO.File]::Delete("$($Folder)\$($Log)")
                                }
                                $false {
                                    # Rename log to +1
                                    $NewFileName = $Log -replace "_([0-9]+)\.lo_$", "_$($LogFileNumber+1).lo_"
                                    [System.IO.File]::Copy("$($Folder)\$($Log)", "$($Folder)\$($NewFileName)", $true)
                                }
                            }
                        }

                        # Copy main log to _1.lo_
                        [System.IO.File]::Copy($LogFilePath, "$($Folder)\$($LogFileNameWithoutExt)_1.lo_", $true)

                        # Blank the main log
                        $StreamWriter = New-Object -TypeName System.IO.StreamWriter -ArgumentList $LogFilePath, $false
                        $StreamWriter.Close()
                    }
                }
                #endregion rename current file if $MaxLogFileSize exceeded, respecting $LogsToKeep
            }
        }
        #endregion log rollover check if $MaxLogFileSize is greater than 0

        # Construct date for log entry
        $Date = (Get-Date -Format 'MM-dd-yyyy')

        # Construct context for log entry
        $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)
    }
    process {
        foreach ($MSG in $Value) {
            #region construct time stamp for log entry based on $Bias and current time
            $Time = switch -regex ($Bias) {
                '-' {
                    [string]::Concat($(Get-Date -Format 'HH:mm:ss.fff'), $Bias)
                }
                Default {
                    [string]::Concat($(Get-Date -Format 'HH:mm:ss.fff'), '+', $Bias)
                }
            }
            #endregion construct time stamp for log entry based on $Bias and current time

            #region construct the log entry according to CMTrace format
            $LogText = [string]::Format('<![LOG[{0}]LOG]!><time="{1}" date="{2}" component="{3}" context="{4}" type="{5}" thread="{6}" file="">', $MSG, $Time, $Date, $Component, $Context, $LogLevel, $PID)
            #endregion construct the log entry according to CMTrace format

            #region add value to log file
            try {
                $StreamWriter = New-Object -TypeName System.IO.StreamWriter -ArgumentList $LogFilePath, 'Append'
                $StreamWriter.WriteLine($LogText)
                $StreamWriter.Close()
            }
            catch [System.Exception] {
                Write-Warning -Message "Unable to append log entry to $FileName file. Error message: $($_.Exception.Message)"
            }
            #endregion add value to log file
        }
    }
}
#EndRegion '.\Public\Write-CCMLogEntry.ps1' 122