ChocoCCM.psm1

if(-not (Test-Path $env:ChocolateyInstall\license\chocolatey.license.xml)){
    throw "A licensed version of Chocolatey For Business is required to import and use this module"
}

function Add-CCMGroup {
    <#
    .SYNOPSIS
    Adds a group to Central Management
     
    .DESCRIPTION
    Deployments in Central Management revolve around Groups. Before you can execute a deployment you must define a target group of computers the Deployment will execute on.
    Use this function to create new groups in your Central Management system
     
    .PARAMETER Name
    The name you wish to give the group
     
    .PARAMETER Description
    A short description of the group
     
    .PARAMETER Group
    The group(s) to include as members
     
    .PARAMETER Computer
    The computer(s) to include as members
     
    .EXAMPLE
    Add-CCMGroup -Name PowerShell -Description "I created this via the ChocoCCM module" -Computer pc1,pc2
 
    .EXAMPLE
    Add-CCMGroup -Name PowerShell -Description "I created this via the ChocoCCM module" -Group Webservers
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/add-ccmgroup")]
    param(
        [parameter(mandatory = $true)]
        [string]
        $Name,
        
        [parameter()]
        [string]
        $Description,

        [parameter()]
        [string[]]
        $Group,

        [parameter()]
        [string[]]
        $Computer
    )

    begin {

        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        
        $computers = Get-CCMComputer
        $groups = Get-CCMGroup

        $ComputerCollection = [System.Collections.Generic.List[psobject]]::new()
        $GroupCollection = [System.Collections.Generic.List[psobject]]::new()

        foreach ($c in $Computer) {
            $Cresult = $computers | Where-Object { $_.Name -eq "$c" } | Select-Object Name,Id
            $ComputerCollection.Add($Cresult)
        }

        foreach ($g in $Group) {
            $Gresult = $groups | Where-Object { $_.Name -eq "$g" } | Select-Object Name,Id
            $GroupCollection.Add($Gresult)
        }

    }

    process {

        $irmParams = @{
            Uri         = "$($protocol)://$hostname/api/services/app/Groups/CreateOrEdit"
            Method      = "post"
            ContentType = "application/json"
            Body        = @{
                Name        = $Name
                Description = $Description
                Groups      = @($GroupCollection | ForEach-Object { [pscustomobject]@{ computerId ="$($_.id)" }})
                Computers   = @($ComputerCollection | ForEach-Object { [pscustomobject]@{ computerId = "$($_.id)"}})
            } | ConvertTo-Json
            WebSession  = $Session
        }
    
        try {
            $response = Invoke-RestMethod @irmParams -ErrorAction Stop
        }
    
        catch {
            throw $_.Exception.Message
        }

        [pscustomobject]@{
            name = $Name
            description = $Description
            groups = $GroupCollection
            computers = $ComputerCollection
        }
    }

}
function Add-CCMGroupMember {
    <#
    .SYNOPSIS
    Adds a member to an existing Group in Central Management
     
    .DESCRIPTION
    Add new computers and groups to existing Central Management Groups
     
    .PARAMETER Name
    The group to edit
     
    .PARAMETER Computer
    The computer(s) to add
     
    .PARAMETER Group
    The group(s) to add
     
    .EXAMPLE
    Add-CCMGroupMember -Group 'Newly Imaged' -Computer Lab1,Lab2,Lab3
     
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/add-ccmgroup-member")]
    param(
        [parameter(Mandatory = $true)]
        [parameter(ParameterSetName = "Computer")]
        [parameter(ParameterSetName = "Group")]
        [ArgumentCompleter(
            {
                param($Command,$Parameter,$WordToComplete,$CommandAst,$FakeBoundParams)
                $r = (Get-CCMGroup).Name
                

                If($WordToComplete){
                    $r.Where{$_ -match "^$WordToComplete"}
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Name,
        
        [parameter(Mandatory = $true, ParameterSetName = "Computer")]
        [string[]]
        $Computer,

        [parameter(ParameterSetName = "Group")]
        [string[]]
        $Group
    )

    begin {
        
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        
        $computers = Get-CCMComputer
        $groups = Get-CCMGroup
    
        $ComputerCollection = [System.Collections.Generic.List[psobject]]::new()
        $GroupCollection = [System.Collections.Generic.List[psobject]]::new()

        $id  = Get-CCMGroup -Group $name | Select-Object -ExpandProperty Id
        $current = Get-CCMGroup -Id $id| Select-Object computers
        $current.computers | ForEach-Object { $ComputerCollection.Add($($_.computerId))}
        #$current.id | % {$ComputerCollection.Add($_)}
        
    }

    process {

        switch($PSCmdlet.ParameterSetName){
            'Computer' {

                foreach ($c in $Computer) {
                    $Cresult = $computers | Where-Object { $_.Name -eq "$c" } | Select-Object -ExpandProperty Id
                    $ComputerCollection.Add($Cresult)
                }

                $processedComputers = @($ComputerCollection | ForEach-Object { [pscustomobject]@{ computerId = "$_"}})
                
            }

            'Group' {

                foreach ($g in $Group) {
                    $Gresult = $groups | Where-Object { $_.Name -eq "$g" } | Select-Object -ExpandProperty Id
                    $GroupCollection.Add($Gresult)
                }
                    $processedGroups = @($GroupCollection | ForEach-Object { [pscustomobject]@{ computerId ="$_" }})
                }
            }
        

        $irmParams = @{
            Uri         = "$($protocol)://$hostname/api/services/app/Groups/CreateOrEdit"
            Method      = "post"
            ContentType = "application/json"
            Body        = @{
                Name        = $Name
                Id          = ($groups | Where-Object { $_.name -eq "$Name"} | Select-Object  -ExpandProperty Id)
                Description = ($groups | Where-Object { $_.name -eq "$Name"} | Select-Object  -ExpandProperty Description)
                Groups      = $processedGroups
                Computers   = $processedComputers
            } | ConvertTo-Json
            WebSession  = $Session
        }

        try {
            $null = Invoke-RestMethod @irmParams -ErrorAction Stop
        }

        catch {
            throw $_.Exception.Message
        }
    }
}
function Connect-CCMServer {
    <#
    .SYNOPSIS
    Creates a session to a central management instance
     
    .DESCRIPTION
    Creates a web session cookie used for other functions in the ChocoCCM module
     
    .PARAMETER Hostname
    The hostname and port number of your Central Management installation
     
    .PARAMETER Credential
    The credentials for your Central Management installation. You'll be prompted if left blank
     
    .EXAMPLE
    Connect-CCMServer -Hostname localhost:8090
 
    .EXAMPLE
    $cred = Get-Credential ; Connect-CCMServer -Hostname localhost:8090 -Credential $cred
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/connect-ccmserver")]
    Param(
        [Parameter(Mandatory,Position=0)]
        [String]
        $Hostname,

        [Parameter(Mandatory)]
        [System.Management.Automation.PSCredential]
        $Credential,

        [Parameter()]
        [switch]
        $UseSSL
    )

        begin{
            $script:Hostname = $Hostname
            $protocol = 'http'
        }
        process {

            if($UseSSL){
                $protocol = 'https'
            }
            $body = @{
                usernameOrEmailAddress = "$($Credential.UserName)"
                password = "$($Credential.GetNetworkCredential().Password)"
            }

            $Result = Invoke-WebRequest -Uri "$($protocol)://$Hostname/Account/Login" -Method POST -ContentType 'application/x-www-form-urlencoded' -Body $body -SessionVariable Session -Erroraction Stop
            
            $Script:Session = $Session
            $Script:Protocol = $protocol

        }
    
}
function Disable-CCMDeployment {
    <#
    .SYNOPSIS
    Archive a CCM Deployment. This will move a Deployment to the Archived Deployments section in the Central Management Web UI.
     
    .DESCRIPTION
    Moves a deployment in Central Management to the archive. This Deployment will no longer be available for use.
     
    .PARAMETER Deployment
    The deployment to archive
     
    .EXAMPLE
    Disable-CCMDeployment -Deployment 'Upgrade VLC'
 
    .EXAMPLE
    Archive-CCMDeployment -Deployment 'Upgrade VLC'
     
    #>

    [Alias('Archive-CCMDeployment')]
    [cmdletBinding(ConfirmImpact = "high", SupportsShouldProcess,HelpUri="https://chocolatey.org/docs/disable-ccmdeployment")]
    param(
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMDeployment).Name
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Deployment
    )
    begin {

        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        
        $deployId = Get-CCMDeployment -Name $Deployment | Select-Object -ExpandProperty Id
    }
    process {
    
        if ($PSCmdlet.ShouldProcess("$Deployment", "ARCHIVE")) {
            $irmParams = @{
                Uri         = "$($protocol)://$hostname/api/services/app/DeploymentPlans/Archive"
                Method      = "POST"
                ContentType = "application/json"
                Body        = @{ id = "$deployId" } | ConvertTo-Json
                Websession  = $Session
            }

            try {
                $null = Invoke-RestMethod @irmParams -ErrorAction Stop
            }
            catch {
                throw $_.Exception.Message
            }
        }
    }
}
function Export-CCMDeployment {
    <#
    .SYNOPSIS
    Exports a Deployment to a CliXML file
     
    .DESCRIPTION
    Adds ability to export a deployment as cli-xml. Useful for backup/source control of deployments
 
    .PARAMETER Deployment
    The CCM Deployment to Export
     
    .PARAMETER DeploymentStepsOnly
    Only export a deployment's steps
     
    .PARAMETER OutFile
    The xml file to save the deployment as
     
    .PARAMETER AllowClobber
    Allow a file to be overwritten if it already exists
     
    .EXAMPLE
    Export-CCMDeployment -Deployment TestDeployment -OutFile C:\temp\testdeployment.xml
 
    .EXAMPLE
    Export-CCMDeployment -Deployment UpgradeChrome -OutFile C:\temp\upgradechrome_ccmdeployment.xml -AllowClobber
     
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/export-ccmdeployment")]
    param(
        [Parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMDeployment -All).Name
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Deployment,

        [Parameter()]
        [Switch]
        $DeploymentStepsOnly,

        [Parameter(Mandatory)]
        [String]
        $OutFile,

        [Parameter()]
        [Switch]
        $AllowClobber
    )

    process {

        $exportParams = if ($AllowClobber) {
            @{
                Force = $true
            } 
        } else {
            @{}
        }
        $DeploymentObject = Get-CCMDeployment -Name $Deployment

        if ($DeploymentStepsOnly) {
            $DeploymentObject.deploymentSteps | Export-Clixml -Depth 10 -Path $OutFile -Force @exportParams
        } else {
            $DeploymentObject | Export-Clixml -Depth 10 -Path $OutFile @exportParams
        }
    }
}
function Export-CCMDeploymentReport {
    <#
    .SYNOPSIS
    Downloads a deployment report from Central Management. This will be saved in the path you specify for OutputFolder
     
    .DESCRIPTION
    Downloads a deployment report from Central Management in PDF or Excel format. The file is saved to the OutputFolder
     
    .PARAMETER Deployment
    The deployment from which to generate and download a report
     
    .PARAMETER Type
    The type of report, either PDF or Excel
     
    .PARAMETER OutputFolder
    The path to save the report too
     
    .EXAMPLE
    Export-CCMDeploymentReport -Deployment 'Complex' -Type PDF -OutputFolder C:\temp\
 
    .EXAMPLE
    Export-CCMDeploymentReport -Deployment 'Complex -Type Excel -OutputFolder C:\CCMReports
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/export-ccmdeployment-report")]
    param([ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMDeployment -All).Name
        

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Deployment,

        [parameter(Mandatory)]
        [ValidateSet('PDF', 'Excel')]
        [string]
        $Type,

        [parameter(Mandatory)]
        [ValidateScript( { Test-Path $_ })]
        [string]
        $OutputFolder
    )
    begin {

        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        
        $deployId = Get-CCMDeployment -Name $Deployment | Select-Object -ExpandProperty Id
    }
    process {

        $irmParams = @{
            Method      = "Get"
            ContentType = "application/json"
            WebSession  = $Session
        }

        switch ($Type) {
            'PDF' {
                $url = "$($protocol)://$hostname/api/services/app/DeploymentPlans/GetDeploymentPlanDetailsToPdf?deploymentPlanId=$deployId"
            }
            'Excel' { $url = "$($protocol)://$hostname/api/services/app/DeploymentPlans/GetDeploymentPlanDetailsToExcel?deploymentPlanId=$deployId" }
        }

        $irmParams.Add('Uri', "$url")

        try {
            $record = Invoke-RestMethod @irmParams -ErrorAction Stop            
            $fileName = $record.result.fileName
            $fileType = $record.result.fileType
            $fileToken = $record.result.fileToken
        }
        catch {
            throw $_.Exception
        }

        $downloadParams = @{
            Uri         = "$($protocol)://$hostname/File/DownloadTempFile?fileType=$fileType&fileToken=$fileToken&fileName=$fileName"
            OutFile     = "$($OutputFolder)\$($fileName)"
            WebSession  = $Session
            Method      = "GET"
            ContentType = $fileType
        }

        try {
            $dl = Invoke-RestMethod @downloadParams -ErrorAction Stop
        }

        catch {
            $_.ErrorDetails
        }

    }
}
function Export-CCMOutdatedSoftwareReport {
    <#
    .SYNOPSIS
    Download an outdated Software report from Central Management. This file will be saved to the OutputFolder specified
     
    .DESCRIPTION
    Download either a PDF or Excel format report of outdated software from Central Management to the OutputFolder specified
     
    .PARAMETER Report
    The report to download
     
    .PARAMETER Type
    Specify either PDF or Excel
     
    .PARAMETER OutputFolder
    The path to save the file
     
    .EXAMPLE
    Export-CCMOutdatedSoftwareReport -Report '7/4/2020 6:44:40 PM' -Type PDF -OutputFolder C:\CCMReports
     
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/export-ccmoutdated-software-report")]
    param(
        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMOutdatedSoftwareReport).creationTime
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Report,
        [parameter(Mandatory)]
        [ValidateSet('PDF', 'Excel')]
        [string]
        $Type,

        [parameter(Mandatory)]
        [ValidateScript( { Test-Path $_ })]
        [string]
        $OutputFolder
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }

    process {

        $reportId = Get-CCMOutdatedSoftwareReport | Where-Object { $_.creationTime -eq "$Report" } | Select -ExpandProperty id

        $irmParams = @{
            Method      = "Get"
            ContentType = "application/json"
            WebSession  = $Session
        }

        switch ($Type) {
            'PDF' { $url = "$($protocol)://$hostname/api/services/app/OutdatedReports/GetOutdatedSoftwareToPdf?reportId=$reportId" }
            'Excel' { $url = "$($protocol)://$hostname/api/services/app/OutdatedReports/GetOutdatedSoftwareToExcel?reportId=$reportId" }
        }

        $irmParams.Add('Uri', "$url")

        try {
            $record = Invoke-RestMethod @irmParams -ErrorAction Stop
            $fileName = $record.result.fileName
            $fileType = $record.result.fileType
            $fileToken = $record.result.fileToken
        }
        catch {
            throw $_.Exception
        }

        $downloadParams = @{
            Uri         = "$($protocol)://$hostname/File/DownloadTempFile?fileType=$fileType&fileToken=$fileToken&fileName=$fileName"
            OutFile     = "$($OutputFolder)\$($fileName)"
            WebSession  = $Session
            Method      = "GET"
            ContentType = $fileType
        }

        try {
            $dl = Invoke-RestMethod @downloadParams -ErrorAction Stop
        }

        catch {
            $_.ErrorDetails
        }

    }
}
Function Get-CCMComputer {
    <#
    .SYNOPSIS
    Returns information about computers in CCM
     
    .DESCRIPTION
    Query for all, or by computer name/id to retrieve information about the system as reported in Central Management
     
    .PARAMETER Computer
    Returns the specified computer(s)
     
    .PARAMETER Id
    Returns the information for the computer with the specified id
     
    .EXAMPLE
    Get-CCMComputer
 
    .EXAMPLE
    Get-CCMComputer -Computer web1
 
    .EXAMPLE
    Get-CCMComputer -Id 13
     
    .NOTES
     
    #>

    [cmdletBinding(DefaultParameterSetName = "All",HelpUri="https://chocolatey.org/docs/get-ccmcomputer")]
    Param(

        [Parameter(Mandatory, ParameterSetName = "Computer")]
        [string[]]
        $Computer,

        [Parameter(Mandatory, ParameterSetName = "Id")]
        [int]
        $Id

    )

    begin {
        If (-not $Session) {

            throw "Unauthenticated! Please run Connect-CCMServer first"

        }

    }

    process {

        if (-not $Id) {
            $records = Invoke-RestMethod -Uri "$($protocol)://$Hostname/api/services/app/Computers/GetAll" -WebSession $Session
        } 
        
        Switch ($PSCmdlet.ParameterSetName) {
          

            "Computer" {
                
                Foreach ($c in $computer) {

                    [pscustomobject]$records.result | Where-Object { $_.name -match "$c" } 
                
                }

            }

            "Id" {

                $records = Invoke-RestMethod -Uri "$($protocol)://$Hostname/api/services/app/Computers/GetComputerForEdit?Id=$Id" -WebSession $Session
                $records

            }

            default {
                
                $records.result
    
            }
            

        }
       
    }
    
}
function Get-CCMDeployment {
    <#
    .SYNOPSIS
    Return information about a CCM Deployment
     
    .DESCRIPTION
    Returns detailed information about Central Management Deployment Plans
     
    .PARAMETER Name
    Returns the named Deployment Plan
     
    .PARAMETER Id
    Returns the Deployment Plan with the give Id
     
    .EXAMPLE
    Get-CCMDeployment
     
    .EXAMPLE
    Get-CCMDeployment -Name Bob
 
    .EXAMPLE
    Get-CCMDeployment -Id 583
    #>

    [cmdletBinding(DefaultParameterSetname="default",HelpUri="https://chocolatey.org/docs/get-ccmdeployment")]
    param(
        
        [parameter(ParameterSetName="Name",Mandatory)]
        [string]
        $Name,

        [Parameter(ParameterSetName="Id",Mandatory)]
        [string]
        $Id
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }

    process {

        if (-not $Id) {
            $records = Invoke-RestMethod -Uri "$($protocol)://$Hostname/api/services/app/DeploymentPlans/GetAll" -WebSession $Session
        } 

        switch($PSCmdlet.ParameterSetName){

            'Name' {
                
                $queryId = $records.result | Where-Object { $_.Name -eq "$Name"} | Select-Object -ExpandProperty Id
                $records = Invoke-RestMethod -Uri "$($protocol)://$Hostname/api/services/app/DeploymentPlans/GetDeploymentPlanForView?Id=$queryId" -WebSession $Session
                $records.result.deploymentPlan

            }

            'Id' {
                $records = Invoke-RestMethod -Uri "$($protocol)://$Hostname/api/services/app/DeploymentPlans/GetDeploymentPlanForView?Id=$id" -WebSession $Session
                $records.result.deploymentPlan
            }

            default {
                $records.result
            }
            
        }
    }
}
function Get-CCMGroup {
    <#
    .SYNOPSIS
    Returns group information for your CCM installation
     
    .DESCRIPTION
    Returns information about the groups created in your CCM Installation
     
    .PARAMETER Group
    Returns group with the provided name
     
    .PARAMETER Id
    Returns group withe the provided id
     
    .EXAMPLE
    Get-CCMGroup
 
    .EXAMPLE
    Get-CCMGroup -Id 1
 
    .EXAMPLE
    Get-CCMGroup -Group 'Web Servers'
     
    #>

    [cmdletBinding(DefaultParameterSetName="default",HelpUri="https://chocolatey.org/docs/get-ccmgroup")]
    param(

        [parameter(Mandatory, ParameterSetName = "Group")]
        [string[]]
        $Group,

        [parameter(Mandatory, ParameterSetName = "Id")]
        [String[]]
        $Id
    )

    begin {
        If (-not $Session) {

            throw "Unauthenticated! Please run Connect-CCMServer first"

        }

    }
    process {
        if (-not $Id) {
            $records = Invoke-RestMethod -Method Get -Uri "$($protocol)://$hostname/api/services/app/Groups/GetAll" -WebSession $Session
            #$records = Invoke-We -Uri http://$Hostname/api/services/app/Groups/GetAll -WebSession $Session -UseBasicParsing
        } 
        
        Switch ($PSCmdlet.ParameterSetName) {

            "Group" {

                $records.result | Where-Object { $_.name -in $Group }

            }

            "Id" {
                $records = Invoke-RestMethod -Uri "$($protocol)://$Hostname/api/services/app/Groups/GetGroupForEdit?Id=$Id" -WebSession $Session
                $records.result
            }

            default {

                $records.result

            }

        }

    }
}
function Get-CCMGroupMember {
    <#
    .SYNOPSIS
    Returns information about a CCM group's members
     
    .DESCRIPTION
    Return detailed group information from Chocolatey Central Management
     
    .PARAMETER Group
    The Group to query
     
    .EXAMPLE
    Get-CCMGroupMember -Group "WebServers"
     
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/get-ccmgroup-member")]
    param(
        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMGroup -All).Name
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Group
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {
        $Id = (Get-CCMGroup -Group $Group).Id
        $irmParams = @{
            Uri         = "$($protocol)://localhost:8090/api/services/app/Groups/GetGroupForEdit?id=$Id"
            Method      = "GET"
            ContentType = "application/json"
            WebSession  = $Session
        }

        try {
            $record = Invoke-RestMethod @irmParams -ErrorAction Stop
        }
        catch {
            throw $_.Exception.Message
        }

        $cCollection = [System.Collections.Generic.List[psobject]]::new()
        $gCollection = [System.Collections.Generic.List[psobject]]::new()

        $record.result.computers | ForEach-Object {
            $cCollection.Add($_)
        }

        $record.result.groups | ForEach-Object {
            $gCollection.Add($_)
        }
       
        [pscustomobject]@{
            Name        = $record.result.Name
            Description = $record.result.Description
            Groups      = @($gCollection)
            Computers   = @($cCollection)
            CanDeploy   = $record.result.isEligibleForDeployments
        } 

        
    }
}
function Get-CCMOutdatedSoftware {
<#
.SYNOPSIS
Returns all outdated software reported in CCM
 
.DESCRIPTION
Returns all outdated software reported in CCM
 
.EXAMPLE
Get-CCMOutdatedSoftware
#>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/get-ccmoutdated-software")]
    param()
    
    process {
        $r = Get-CCMSoftware | Where-Object { $_.isOutdated -eq $true}
        $r
    }
}
function Get-CCMOutdatedSoftwareMember {
    <#
    .SYNOPSIS
    Returns computers with the requested outdated software. To see outdated software information use Get-CCMOutdatedSoftware
     
    .DESCRIPTION
    Returns the computers with the requested outdated software. To see outdated software information use Get-CCMOutdatedSoftware
     
    .PARAMETER Software
    The software to query. Software here refers to what would show up in Programs and Features on a machine.
    Example: If you have VLC installed, this shows as 'VLC Media Player' in Programs and Features.
     
    .PARAMETER Package
    This is the Chocolatey package name to search for.
     
    .EXAMPLE
    Get-CCMOutdatedSoftwareMember -Software 'VLC Media Player'
 
    .EXAMPLE
    Get-CCMOutdatedSoftwareMember -Package vlc
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/get-ccmoutdated-software-member")]
    param(
        [parameter()]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMSoftware -All | Where-Object { $_.isOutdated -eq $true }).Name
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Software,

        [parameter()]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMSoftware -All | Where-Object { $_.isOutdated -eq $true }).packageId
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Package
    )

    begin {
        if (-not $Session) {
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {

        if ($Software) {
            $id = Get-CCMSoftware -Software $Software | Select-Object -ExpandProperty softwareId

        }

        if ($Package) {
            $id = Get-CCMSoftware -Package $Package | Select-Object -ExpandProperty softwareId

        }

        $id | Foreach-Object {
            $irmParams = @{
                Uri         = "$($protocol)://$hostname/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId?filter=&softwareId=$($_)&skipCount=0&maxResultCount=100"
                Method      = "GET"
                ContentType = "application/json"
                WebSession  = $Session
            }

            try {
                $record = Invoke-RestMethod @irmParams -ErrorAction Stop
            }
            catch {
                $_.Exception.Message
            }

            $record.result.items | Foreach-Object {
                [pscustomobject]@{
                    softwareId     = $_.softwareId
                    software       = $_.software.name
                    packageName    = $_.software.packageId
                    packageVersion = $_.software.packageVersion
                    name           = $_.computer.name
                    friendlyName   = $_.computer.friendlyName
                    ipaddress      = $_.computer.ipaddress
                    fqdn           = $_.computer.fqdn
                    computerid     = $_.computer.id
                
                }
                
            }
        }
    }
}
function Get-CCMOutdatedSoftwareReport {
    <#
    .SYNOPSIS
    List all Outdated Software Reports generated in Central Management
     
    .DESCRIPTION
    List all Outdated Software Reports generated in Central Management
     
    .EXAMPLE
    Get-CCMOutdatedSoftwareReport
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/get-ccmoutdated-software-report")]
    param()

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {
        $irmParams =  @{
            Uri = "$($protocol)://$hostname/api/services/app/Reports/GetAllPaged?reportTypeFilter=1"
            Method = "Get"
            ContentType = "application/json"
            WebSession = $Session
        }

         try {
             $response = Invoke-RestMethod @irmParams
         }
         catch{
             throw $_.Exception.Message
         }

         $response.result.items | % {
            [pscustomobject]@{
                reportType = $_.report.reportType -as [String]
                creationTime = $_.report.creationTime -as [String]
                id = $_.report.id -as [string]
            }


         }
         
    }
}
function Get-CCMOutdatedSoftwareReportDetail {
    <#
    .SYNOPSIS
    View detailed information about an Outdated Software Report
     
    .DESCRIPTION
    Return report details from an Outdated Software Report in Central Management
     
    .PARAMETER Report
    The report to query
     
    .EXAMPLE
    Get-CCMOutdatedSoftwareReportDetail -Report '7/4/2020 6:44:40 PM'
     
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/get-ccmoutdated-software-report-detail")]
    param(
        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMOutdatedSoftwareReport).creationTime
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Report
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {
        $reportId = Get-CCMOutdatedSoftwareReport | Where-Object {$_.creationTime -eq "$Report"} | Select -ExpandProperty id

        $irmParams = @{
            Uri = "$($protocol)://$hostname/api/services/app/OutdatedReports/GetAllByReportId?reportId=$reportId&sorting=outdatedReport.packageDisplayText%20asc&skipCount=0&maxResultCount=200"
            Method = "Get"
            ContentType = "application/json"
            WebSession = $Session
        }

        try{
            $response = Invoke-RestMethod @irmParams -ErrorAction Stop
        }
        catch {
            throw $_.Exception.Message
        }

        $response.result.items.outdatedReport

    }
}
function Get-CCMRole {
    <#
    .SYNOPSIS
    Get roles available in Chococlatey Central Management
     
    .DESCRIPTION
    Return information about roles available in Chocolatey Central Management
     
    .PARAMETER Name
    The name of a role to query
 
    .EXAMPLE
    Get-CCMRole
 
    .EXAMPLE
    Get-CCMRole -Name CCMAdmin
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/get-ccmrole")]
    param(

    [parameter(ParameterSetName="Name")]
        [string]
        $Name

    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {

        $irmParams = @{
            Uri = "$($protocol)://$hostname/api/services/app/Role/GetRoles?permission="
            Method = "GET"
            ContentType = "application/json"
            WebSession = $Session
        }

        try{
            $response = Invoke-RestMethod @irmParams -ErrorAction Stop
        } catch {
            throw $_.Exception.Message
        }

        switch($PSCmdlet.ParameterSetName){

            'Name' {
                $response.result.items | Where-Object { $_.name -eq $Name }
            }

            default {
                $response.result.items
            }
        }
    }
}
Function Get-CCMSoftware {
    <#
    .SYNOPSIS
    Returns information about software tracked inside of CCM
     
    .DESCRIPTION
    Return information about each piece of software managed across all of your estate inside Central Management
     
    .PARAMETER Software
    Return information about a specific piece of software by friendly name
 
    .PARAMETER Package
    Return information about a specific package
     
    .PARAMETER Id
    Return information about a specific piece of software by id
     
    .EXAMPLE
    Get-CCMSoftware
 
    .EXAMPLE
    Get-CCMSoftware -Software 'VLC Media Player'
 
    .EXAMPLE
    Get-CCMSoftware -Package vlc
 
    .EXAMPLE
    Get-CCMSoftware -Id 37
     
    .NOTES
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/get-ccmsoftware")]
    Param(
            
        [Parameter(Mandatory, ParameterSetName = "Software")]
        [string]
        $Software,
        
        [Parameter(Mandatory, ParameterSetName = "Package")]
        [string]
        $Package,

        [Parameter(Mandatory, ParameterSetName = "Id")]
        [int]
        $Id

    )

    begin {
        if (-not $Session) {
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }

    process {

        if (-not $Id) {
            $records = Invoke-RestMethod -Uri "$($protocol)://$Hostname/api/services/app/Software/GetAll" -WebSession $Session -UseBasicParsing
        } 
        
        Switch ($PSCmdlet.ParameterSetName) {

            "Software" {
                $softwareId = $records.result.items | Where-Object { $_.name -eq "$Software" } | Select-Object -ExpandProperty Id

                $irmParams = @{
                    WebSession = $Session
                    Uri        = "$($protocol)://$Hostname/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId?filter=&softwareId=$softwareID&skipCount=0&maxResultCount=500"
                }
                
                $records = Invoke-RestMethod @irmParams
                $records.result.items

            }

            "Package" {
                $packageId = $records.result.items | Where-Object { $_.packageId -eq "$Package" } | Select-Object -ExpandProperty id

                $packageId | ForEach-Object {
                    $irmParams = @{
                        WebSession = $Session
                        Uri        = "$($protocol)://$Hostname/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId?filter=&softwareId=$($_)&skipCount=0&maxResultCount=500"
                    }
                
                    $records = Invoke-RestMethod @irmParams
                    $records.result.items
                }
            }

            "Id" {

                $irmParams = @{
                    WebSession = $Session
                    Uri        = "$($protocol)://$Hostname/api/services/app/ComputerSoftware/GetAllPagedBySoftwareId?filter=&softwareId=$Id&skipCount=0&maxResultCount=500"
                }
                $records = Invoke-RestMethod @irmParams
                $records.result.items
            }

            default {
                $records.result.items
            }

        }
       
    }
}
function Get-DeploymentResult {
    <#
    .SYNOPSIS
    Return the result of a Central Management Deployment
     
    .DESCRIPTION
    Return the result of a Central Management Deployment
     
    .PARAMETER Deployment
    The Deployment for which to return information
     
    .EXAMPLE
    Get-CCMDeploymentResult -Name 'Google Chrome Upgrade'
     
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/get-deployment-result")]
    param(
        [Parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMDeployment -All).Name
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Deployment
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        $deployId = Get-CCMDeployment -Name $Deployment | Select-Object -ExpandProperty Id

    }

    process {

        $irmParams = @{
            Uri = "$($protocol)://$hostname/api/services/app/DeploymentSteps/GetAllPagedByDeploymentPlanId?resultFilter=Success%2CFailed%2CUnreachable%2CInconclusive%2CReady%2CActive%2CCancelled%2CUnknown%2CDraft&deploymentPlanId=$deployId&sorting=planOrder%20asc&skipCount=0&maxResultCount=10"
            Method = "GET"
            ContentType = "application/json"
            WebSession = $Session
        }

        try {
            $records = Invoke-RestMethod @irmParams -ErrorAction Stop
            $records.result.items
        }
        catch{
            throw $_.Exception.Message
        }
    }
}
function Import-PDQDeployPackage {
    <#
    .SYNOPSIS
    Imports a PDQ Deploy package as a Central Management Deployment
     
    .DESCRIPTION
    Imports a PDQ Deploy package as a Central Management Deployment
     
    .PARAMETER PdqXml
    The pdq xml file to import
     
    .EXAMPLE
    Import-PDQDeployPackage
     
    .NOTES
    General notes
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/import-pdqdeploy-package")]
    param(
        [parameter(Mandatory)]
        [ValidateScript( { Test-Path $_ })]
        [String]
        $PdqXml
    )

    process {
        [xml]$xmlData = Get-Content $PdqXml

        $deploymentName = $xmlData.SelectNodes("//*[Name]").Name
        $deploymentName = "PDQ Import: $deploymentName"
        
        Write-Verbose "Adding deployment with name: $deploymentName"
        New-CCMDeployment -Name $deploymentName

        $deploymentSteps = $xmldata.SelectNodes("//*[Steps]").Steps

        $deploymentSteps = $deploymentSteps | ForEach-Object {

            if ($_.InstallStep) {
        
                $_.InstallStep | Foreach-Object { 
                    [pscustomobject]@{
                        SuccessCodes  = @($_.SuccessCodes)
                        FailureAction = $_.ErrorMode
                        Type          = switch ($_.Typename) {
                            'Install' { "Basic" }
                        }
                        Package       = $deploymentName
                        Title         = if ($_.title) { $_.title } else { "Install $deploymentName" }
                    }
                }
            }
        }

        $ccmSteps = @{
            Type           = $deploymentSteps.Type
            ValidExitCodes = $deploymentSteps.SuccessCodes
        }

        if ($deploymentSteps.FailureAction -eq 'StopdeploymentFail') {
            $ccmSteps.Add('FailOnError', $true)
        }
        else {
            $ccmSteps.Add('FailOnError', $false)
        }

        if ($deploymentSteps.Type -eq 'Basic') {
            $ccmSteps.Add('ChocoCommand', 'upgrade')
            $ccmSteps.add('Package', '7-zip')
        }

        Write-Verbose "Adding steps from imported package to Deployment"
        New-CCMDeploymentStep -Deployment $deploymentName -Name $deploymentSteps.Title @ccmSteps

    }
    
    end {
        Write-Warning "No targets will be defined for this deployment"
    }
}
function Move-CCMDeploymentToReady {
<#
    .SYNOPSIS
    Moves a deployment to Ready state
     
    .DESCRIPTION
    Moves a Deployment to the Ready state so it can start
     
    .PARAMETER Deployment
    The deployment to move
     
    .EXAMPLE
    Move-CCMDeploymentToReady -Deployment 'Upgrade Outdated VLC'
 
    .EXAMPLE
    Move-CCMDeploymenttoReady -Deployment 'Complex Deployment'
     
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/move-ccmdeployment-to-ready")]
    param(
        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = Get-CCMDeployment -All
                

                If ($WordToComplete) {
                    $r.name.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r.name
                }
            }
        )]
        [string]
        $Deployment
    )

    Begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        
        $id = (Get-CCMDeployment -Name $Deployment).id

    }
    process {

        $irmParams = @{
            Uri         = "$($protocol)://$hostname/api/services/app/DeploymentPlans/MoveToReady"
            Method      = "POST"
            ContentType = "application/json"
            Body        = @{ id = "$id" } | ConvertTo-Json
            WebSession  = $Session
        }

        try {
            $null = Invoke-RestMethod @irmParams -ErrorAction Stop
        }
        catch {
            throw $_.Exception.Message
        }
        
    }
}
function New-CCMDeployment {
    <#
    .SYNOPSIS
    Create a new CCM Deployment Plan
     
    .DESCRIPTION
    Creates a new CCM Deployment. This is just a shell. You'll need to add steps with New-CCMDeploymentStep.
     
    .PARAMETER Name
    The name for the deployment
     
    .EXAMPLE
    New-CCMDeployment -Name 'This is awesome'
     
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/new-ccmdeployment")]
    param(
        [parameter(Mandatory)]
        [string]
        $Name
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {

        $irmParams = @{
            Uri = "$($protocol)://$hostname/api/services/app/DeploymentPlans/CreateOrEdit"
            Method = "POST"
            ContentType = "application/json"
            Body = @{ Name = "$Name"} | ConvertTo-Json
            WebSession = $Session
        }

        try{
            $record = Invoke-RestMethod @irmParams -ErrorAction Stop
        }

        catch {
            throw $_.Exception.Message
        }

        [pscustomobject]@{
            name = $Name
            id = $record.result.id
        }
    }
}
function New-CCMDeploymentStep {
    <#
    .SYNOPSIS
    Adds a Deployment Step to a Deployment Plan
 
    .DESCRIPTION
    Adds both Basic and Advanced steps to a Deployment Plan
 
    .PARAMETER Deployment
    The Deployment where the step will be added
 
    .PARAMETER Name
    The Name of the step
 
    .PARAMETER TargetGroup
    The group(s) the step will target
 
    .PARAMETER ExecutionTimeoutSeconds
    How long to wait for the step to timeout. Defaults to 14400 (4 hours)
 
    .PARAMETER FailOnError
    Fail the step if there is an error. Defaults to True
 
    .PARAMETER RequireSuccessOnAllComputers
    Ensure all computers are successful before moving to the next step.
 
    .PARAMETER ValidExitCodes
    Valid exit codes your script can emit. Default values are: '0','1605','1614','1641','3010'
 
    .PARAMETER Type
    Either a Basic or Advanced Step
 
    .PARAMETER ChocoCommand
    Select from Install,Upgrade, or Uninstall. Used with a Simple step type.
 
    .PARAMETER PackageName
    The chocolatey package to use with a simple step.
 
    .PARAMETER Script
    A scriptblock your Advanced step will use
 
    .EXAMPLE
    New-CCMDeploymentStep -Deployment PowerShell -Name 'From ChocoCCM' -TargetGroup WebServers -Type Basic -ChocoCommand upgrade -PackageName firefox
 
    .EXAMPLE
    New-CCMDeploymentStep -Deployment PowerShell -Name 'From ChocoCCM' -TargetGroup All,PowerShell -Type Advanced -Script { $process = Get-Process
>>
>> Foreach($p in $process){
>> Write-Host $p.PID
>> }
>>
>> Write-Host "end"
>>
>> }
 
    .EXAMPLE
    New-CCMDeploymentStep -Deployment PowerShell -Name 'From ChocoCCM' -TargetGroup All,PowerShell -Type Advanced -Script {(Get-Content C:\script.txt)}
 
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/new-ccmdeployment-step")]
    param(
        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command,$Parameter,$WordToComplete,$CommandAst,$FakeBoundParams)
                $r = (Get-CCMDeployment).Name


                If($WordToComplete){
                    $r.Where{$_ -match "^$WordToComplete"}
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Deployment,

        [parameter(Mandatory)]
        [string]
        $Name,

        [parameter()]
        [ArgumentCompleter(
            {
                param($Command,$Parameter,$WordToComplete,$CommandAst,$FakeBoundParams)
                $r = (Get-CCMGroup).Name


                If($WordToComplete){
                    $r.Where{$_ -match "^$WordToComplete"}
                }

                Else {

                    $r
                }
            }
        )]
        [string[]]
        $TargetGroup = @(),

        [parameter()]
        [string]
        $ExecutionTimeoutSeconds = '14400',

        [parameter()]
        [switch]
        $FailOnError = $true,

        [parameter()]
        [switch]
        $RequireSuccessOnAllComputers = $false,

        [parameter()]
        [string[]]
        $ValidExitCodes = @('0','1605','1614','1641','3010'),

        [parameter(Mandatory,ParameterSetName="StepType")]
        [parameter(Mandatory,ParameterSetName="Basic")]
        [parameter(Mandatory,ParameterSetName="Advanced")]
        [ValidateSet('Basic','Advanced')]
        [string]
        $Type,

        [parameter(Mandatory,ParameterSetName="Basic")]
        [ValidateSet('Install','Upgrade','Uninstall')]
        [string]
        $ChocoCommand,

        [parameter(Mandatory,ParameterSetName="Basic")]
        [string]
        $PackageName,

        [parameter(Mandatory,ParameterSetName="Advanced")]
        [scriptblock]
        $Script
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {

        switch($PSCmdlet.ParameterSetName){
            'Basic' {
                $Body = @{
                    Name = "$Name"
                    DeploymentPlanId = "$(Get-CCMDeployment -Name $Deployment | Select-Object -ExpandProperty Id)"
                    DeploymentStepGroups = @(Get-CCMGroup -Group $TargetGroup | Select-Object Name,Id | ForEach-Object { [pscustomobject]@{groupId = $_.id ; groupName = $_.name}})
                    ExecutionTimeoutInSeconds = "$ExecutionTimeoutSeconds"
                    RequireSuccessOnAllComputers = "$RequireSuccessOnAllComputers"
                    failOnError = "$FailOnError"
                    validExitCodes = "$($validExitCodes -join ',')"
                    script = "$($ChocoCommand.ToLower())|$($PackageName)"

                } | ConvertTo-Json -Depth 3

                $Uri = "$($protocol)://$hostname/api/services/app/DeploymentSteps/CreateOrEdit"


            }

            'Advanced' {
                $Body = @{
                    Name = "$Name"
                    DeploymentPlanId = "$(Get-CCMDeployment -Name $Deployment | Select-Object -ExpandProperty Id)"
                    DeploymentStepGroups = @(Get-CCMGroup -Group $TargetGroup | Select-Object Name,Id | ForEach-Object { [pscustomobject]@{groupId = $_.id ; groupName = $_.name}})
                    ExecutionTimeoutInSeconds = "$ExecutionTimeoutSeconds"
                    RequireSuccessOnAllComputers = "$RequireSuccessOnAllComputers"
                    failOnError = "$FailOnError"
                    validExitCodes = "$($validExitCodes -join ',')"
                    script = "$($Script.ToString())"
                } | ConvertTo-Json -Depth 3

                $Uri = "$($protocol)://$hostname/api/services/app/DeploymentSteps/CreateOrEditPrivileged"


            }
        }

        $irmParams = @{
            Uri = "$($Uri)"
            Method = "POST"
            ContentType = "application/json"
            WebSession = $Session
            Body = $Body

        }

        try{
            $null = Invoke-RestMethod @irmParams -ErrorAction Stop
        }
        catch{
            throw $_.Exception.Message
        }

    }
}
function New-CCMOutdatedSoftwareReport {
    <#
    .SYNOPSIS
    Create a new Outdated Software Report in Central Management
     
    .DESCRIPTION
    Create a new Outdated Software Report in Central Management
     
    .EXAMPLE
    New-CCMOutdatedSoftwareReport
     
    .NOTES
    Creates a new report named with a creation date timestamp in UTC format
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/new-ccmoutdated-software-report")]
    param()

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {
        $irmParams = @{
            Uri = "$($protocol)://$hostname/api/services/app/OutdatedReports/Create"
            Method = "POST"
            ContentType = 'application/json'
            WebSession = $Session
        }

        try {
            $null = Invoke-RestMethod @irmParams -ErrorAction Stop
        }
        catch {
            throw $_.Exception.Message
        }
    }
}
function Remove-CCMDeployment {
    <#
    .SYNOPSIS
    Removes a deployment plan
     
    .DESCRIPTION
    Removes the Deployment Plan selected from a Central Management installation
     
    .PARAMETER Deployment
    The Deployment to delete
     
    .EXAMPLE
    Remove-CCMDeployment -Name 'Super Complex Deployment'
 
    .EXAMPLE
    Remove-CCMDeployment -Name 'Deployment Alpha' -Confirm:$false
     
    #>

    [cmdletBinding(ConfirmImpact = "High", SupportsShouldProcess,HelpUri="https://chocolatey.org/docs/remove-ccmdeployment")]
    param(
        [parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMDeployment -All).Name
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string[]]
        $Deployment
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        $deployId = [System.Collections.Generic.List[string]]::new() 
        
        $Deployment | % { $deployId.Add($(Get-CCMDeployment -Name $_ | Select-Object -ExpandProperty Id)) }
    }
    process {
        
        $deployId | ForEach-Object {
            if ($PSCmdlet.ShouldProcess("$Deployment", "DELETE")) {
                $irmParams = @{
                    Uri = "$($protocol)://$hostname/api/services/app/DeploymentPlans/Delete?Id=$($_)"
                    Method = "DELETE"
                    ContentType = "application/json"
                }
    
                Invoke-RestMethod @irmParams
            }

        }
        
    }
}
function Remove-CCMDeploymentStep {
    <#
    .SYNOPSIS
    Removes a deployment plan
     
    .DESCRIPTION
    Removes the Deployment Plan selected from a Central Management installation
     
    .PARAMETER Deployment
    The Deployment to remove a step from
 
    .PARAMETER Step
    The Step to remove
 
    .EXAMPLE
    Remove-CCMDeploymentStep -Name 'Super Complex Deployment' -Step 'Kill web services'
 
    .EXAMPLE
    Remove-CCMDeploymentStep -Name 'Deployment Alpha' -Step 'Copy Files' -Confirm:$false
     
    #>

    [cmdletBinding(ConfirmImpact = "High", SupportsShouldProcess,HelpUri="https://chocolatey.org/docs/remove-ccmdeployment-step")]
    param(
        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMDeployment)
                

                If ($WordToComplete) {
                    $r.Name.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r.Name
                }
            }
        )]
        [string]
        $Deployment,

        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $d = (Get-CCMDeployment -Name $($FakeBoundParams.Deployment)).id
                $idSteps = (Get-CCMDeployment -Id $d).deploymentSteps.Name

                If ($WordToComplete) {
                    $idSteps.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $idSteps
                }
            }
        )]
        [string]
        $Step

    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        $deployId = Get-CCMDeployment -Name $Deployment | Select-Object -ExpandProperty Id
        $deploymentSteps = Get-CCMDeployment -Id $deployId | Select-Object deploymentSteps
        $stepId = $deploymentSteps.deploymentSteps | Where-Object { $_.Name -eq "$Step"} | Select -ExpandProperty id

    }
    process {
    
        if ($PSCmdlet.ShouldProcess("$Step", "DELETE")) {
            $irmParams = @{
                Uri = "$($protocol)://$hostname/api/services/app/DeploymentSteps/Delete?Id=$stepId"
                Method = "DELETE"
                ContentType = "application/json"
                WebSession = $Session
            }

            $null = Invoke-RestMethod @irmParams
        }
    }
}
function Remove-CCMGroup {
    <#
    .SYNOPSIS
    Removes a CCM group
     
    .DESCRIPTION
    Removes a group from Chocolatey Central Management
     
    .PARAMETER Group
    The group(s) to delete
     
    .EXAMPLE
    Remove-CCMGroup -Group WebServers
 
    .EXAMPLE
    Remove-CCMGroup -Group WebServer,TestAppDeployment
 
    .EXAMPLE
    Remove-CCMGroup -Group PilotPool -Confirm:$false
 
    #>

    [cmdletBinding(ConfirmImpact = "High", SupportsShouldProcess,HelpUri="https://chocolatey.org/docs/remove-ccmgroup")]
    param(
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMGroup -All).Name
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string[]]
        $Group
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {

        $Group | ForEach-Object {

            $id = Get-CCMGroup -Group $_ | Select-Object -ExpandProperty Id

            $irmParams = @{
                Uri         = "$($protocol)://$hostname/api/services/app/Groups/Delete?id=$id"
                Method      = "DELETE"
                ContentType = "application/json"
                WebSession  = $Session
            }

            if ($PSCmdlet.ShouldProcess($Group, "DELETE")) {
                
                Write-Verbose -Message "Removing group: $($_) with Id: $($id)"

                try {
                    $null = Invoke-RestMethod @irmParams -ErrorAction Stop
                }

                catch {
                    throw $_.Exception.Message
                }

            }
        }
    }
}
function Remove-CCMGroupMember {
    <#
    .SYNOPSIS
    Remove a member from a Central Management Group
     
    .DESCRIPTION
    Remove a member from a Central Management Group
     
    .PARAMETER Group
    The group you want to remove a member from
     
    .PARAMETER Member
    The member you want to remove
     
    .EXAMPLE
    Remove-CCMGroupMember -Group TestLab -Member TestPC1
    #>

    [cmdletBinding(ConfirmImpact="High",SupportsShouldProcess,HelpUri="https://chocolatey.org/docs/remove-ccmgroup-member")]
    param(
        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command,$Parameter,$WordToComplete,$CommandAst,$FakeBoundParams)
                $r = (Get-CCMGroup -All).Name
                

                If($WordToComplete){
                    $r.Where{$_ -match "^$WordToComplete"}
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Group,

        [parameter(Mandatory)]
        [string]
        $Member
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {

        $id = (Get-CCMGroup -Group $Group).id

        $irmParams  = @{
            Uri = ""
            Method = "DELETE"
            ContentType = "application/json"
            WebSession  = $Session
        }

        try {
            Invoke-RestMethod @irmParams -ErrorAction Stop
        } catch {
            throw $_.Exception.Message
        }
    }
}
function Remove-CCMStaleDeployment {
    <#
    .SYNOPSIS
    Removes stale CCM Deployments
     
    .DESCRIPTION
    Remove stale deployments from CCM based on their age and run status.
     
    .PARAMETER Age
    The age in days to prune
     
    .EXAMPLE
    Remove-StaleCCMDeployment -Age 30
         
    #>

    [cmdletbinding(SupportsShouldProcess, ConfirmImpact = "High",HelpUri="https://chocolatey.org/docs/remove-ccmstale-deployment")]
    param(
        [Parameter(Mandatory)]
        [string]
        $Age
    )

    begin {

    }

    process {
        <#
            Bad States:
            Unknown = 0
            Pending = 2
            Failed = 8
        #>

        $badStates = @(0,2,8)
        if ($PSCmdlet.ShouldProcess("$Deployment", "DELETE")) {
            Get-CCMDeployment -All | Where-Object { $_.CreationDate -ge (Get-Date).AddDays(-$Age) -and $null -eq $_.StartDateTimeUtc -and $_.Result -in $badStates} | Remove-CCMDeployment
        }
    }

}
function Set-CCMDeploymentStep {
    <#
    .SYNOPSIS
    Modify a Deployment Step of a Central Management Deployment
     
    .DESCRIPTION
    Modify a Deployment Step of a Central Management Deployment
     
    .PARAMETER Deployment
    The Deployment to modify
     
    .PARAMETER Step
    The step to modify
     
    .PARAMETER TargetGroup
    Set the target group of the deployment
     
    .PARAMETER ExecutionTimeoutSeconds
    Modify the execution timeout of the deployment in seconds
     
    .PARAMETER FailOnError
    Set the FailOnError flag for the deployment step
     
    .PARAMETER RequireSuccessOnAllComputers
    Set the RequreSuccessOnAllComputers for the deployment step
     
    .PARAMETER ValidExitCodes
    Set valid exit codes for the deployment
     
    .PARAMETER ChocoCommand
    For a basic step, set the choco command to execute. Install, Upgrade, or Uninstall
     
    .PARAMETER PackageName
    For a basic step, the choco package to use in the deployment
     
    .PARAMETER Script
    For an advanced step, this is a script block of PowerShell code to execute in the step
     
    .EXAMPLE
    Set-CCMDeploymentStep -Deployment 'Google Chrome Upgrade' -Step 'Upgrade' -TargetGroup LabPCs -ExecutionTimeoutSeconds 14400 -ChocoCommand Upgrade -PackageName googlechrome
 
    .EXAMPLE
    $stepParams = @{
        Deployment = 'OS Version'
        Step = 'Gather Info'
        TargetGroup = 'US-East servers'
        Script = { $data = Get-WMIObject win32_OperatingSystem
                    [pscustomobject]@{
                        Name = $data.caption
                        Version = $data.version
                    }
        }
    }
 
    Set-CCMDeploymentStep @stepParams
    #>

    [cmdletBinding(DefaultParameterSetName="Dumby",HelpUri="https://chocolatey.org/docs/set-ccmdeployment-step")]
    param(
        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command,$Parameter,$WordToComplete,$CommandAst,$FakeBoundParams)
                $r = (Get-CCMDeployment).Name
                

                If($WordToComplete){
                    $r.Where{$_ -match "^$WordToComplete"}
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Deployment,

        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $d = (Get-CCMDeployment -Name $($FakeBoundParams.Deployment)).id
                $idSteps = (Get-CCMDeployment -Id $d).deploymentSteps.Name

                If ($WordToComplete) {
                    $idSteps.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $idSteps
                }
            }
        )]
        [string]
        $Step,

        [parameter()]
        [ArgumentCompleter(
            {
                param($Command,$Parameter,$WordToComplete,$CommandAst,$FakeBoundParams)
                $r = (Get-CCMGroup -All).Name
                

                If($WordToComplete){
                    $r.Where{$_ -match "^$WordToComplete"}
                }

                Else {

                    $r
                }
            }
        )]
        [string[]]
        $TargetGroup,

        [parameter()]
        [string]
        $ExecutionTimeoutSeconds,

        [parameter()]
        [switch]
        $FailOnError,

        [parameter()]
        [switch]
        $RequireSuccessOnAllComputers,

        [parameter()]
        [string[]]
        $ValidExitCodes,

        [parameter(Mandatory,ParameterSetName="Basic")]
        [ValidateSet('Install','Upgrade','Uninstall')]
        [string]
        $ChocoCommand,

        [parameter(Mandatory,ParameterSetName="Basic")]
        [string]
        $PackageName,

        [parameter(Mandatory,ParameterSetName="Advanced")]
        [scriptblock]
        $Script
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        $deployId = Get-CCMDeployment -Name $Deployment | Select-Object -ExpandProperty Id
        $deploymentSteps = Get-CCMDeployment -Id $deployId | Select-Object deploymentSteps
        $stepId = $deploymentSteps.deploymentSteps | Where-Object { $_.Name -eq "$Step"} | Select -ExpandProperty id



        $existingstepsParams = @{
            Uri = "$($protocol)://$hostname/api/services/app/DeploymentSteps/GetDeploymentStepForView?Id=$stepId"
            Method = "Get"
            ContentType = "application/json"
            WebSession = $Session
        }
        
        try{
            $existingsteps = Invoke-RestMethod @existingstepsParams -Erroraction Stop
        } catch {
            throw $_.Exception.Message
        }

        $existingsteps = $existingsteps.result.deploymentStep
        $existingsteps

    }

    process {

        #So many if statements, so little time
        foreach($param in $PSBoundParameters){

            $param.Name
            $param.Value
            #$existingsteps.$($param.Key) = $param.Value
        }

        #$existingsteps
    }



}
function Set-CCMGroup {
    <#
    .SYNOPSIS
    Change information about a group in Chocolatey Central Management
     
    .DESCRIPTION
    Change the name or description of a Group in Chocolatey Central Management
     
    .PARAMETER Group
    The Group to edit
     
    .PARAMETER NewName
    The new name of the group
     
    .PARAMETER NewDescription
    The new description of the group
     
    .EXAMPLE
    Set-CCMGroup -Group Finance -Description 'Computers in the finance division'
 
    .EXAMPLE
    Set-CCMGroup -Group IT -NewName TheBestComputers
 
    .EXAMPLE
    Set-CCMGroup -Group Test -NewName NewMachineImaged -Description 'Group for freshly imaged machines needing a baseline package pushed to them'
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/set-ccmgroup")]
    param(
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMGroup).Name
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Group,

        [Parameter()]
        [string]
        $NewName,

        [parameter()]
        [string]
        $NewDescription
    )

    begin { 
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }$existing = Get-CCMGroup -Group $Group 
    }
    process {

        if ($NewName) {
            $Name = $NewName
        } else {
            $Name = $existing.name
        }

        if ($NewDescription) {
            $Description = $NewDescription
        } else {
            $Description = $existing.description
        }

        $irmParams = @{
            Uri         = "$($protocol)://$hostname/api/services/app/Groups/CreateOrEdit"
            Method      = "post"
            ContentType = "application/json"
            Body        = @{
                Id          = $($existing.id)
                Name        = $Name
                Description = $Description
                Groups      = @()
                Computers   = @()
            } | ConvertTo-Json
            WebSession  = $Session
        }
    
        try {
            $null = Invoke-RestMethod @irmParams -ErrorAction Stop
        }
    
        catch {
            throw $_.Exception.Message
        }
    }
}
function Set-CCMNotificationStatus {
    <#
    .SYNOPSIS
    Turn notifications on or off in CCM
     
    .DESCRIPTION
    Manage your notification settings in Central Management. Currently only supports On, or Off
     
    .PARAMETER Enable
    Enables notifications
     
    .PARAMETER Disable
    Disables notifications
     
    .EXAMPLE
    Set-CCMNotificationStatus -Enable
 
    .EXAMPLE
    Set-CCMNotificationStatus -Disable
 
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/set-ccmnotification-status")]
    param(
        [parameter(Mandatory,ParameterSetName="Enabled")]
        [switch]
        $Enable,

        [parameter(Mandatory,ParameterSetName="Disabled")]
        [switch]
        $Disable
    )

    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
    }
    process {

        switch($PSCmdlet.ParameterSetName){
            'Enabled' { $status = $true}

            'Disabled'{ $status = $false}
        }

        $irmParams = @{
            Uri = "$($protocol)://$hostname/api/services/app/Notification/UpdateNotificationSettings"
            Method = "PUT"
            ContentType = "application/json"
            WebSession = $Session
            Body = @{
                receiveNotifications = $status
                notifications = @(@{
                    name = "App.NewUserRegistered"
                    isSubscribed = $true
                })
            } | ConvertTo-Json
        }

        try {
            $null = Invoke-RestMethod @irmParams -ErrorAction Stop
        }
        catch {
            throw $_.Exception.Message
        }
    }
}
function Start-CCMDeployment {
    <#
    .SYNOPSIS
    Starts a deployment
     
    .DESCRIPTION
    Starts the specified deployment in Central Management
     
    .PARAMETER Deployment
    The deployment to start
     
    .EXAMPLE
    Start-CCMDeployment -Deployment 'Upgrade Outdated VLC'
 
    .EXAMPLE
    Start-CCMDeployment -Deployment 'Complex Deployment'
     
    #>

    [cmdletBinding(HelpUri="https://chocolatey.org/docs/start-ccmdeployment")]
    param(
        [parameter(Mandatory)]
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = Get-CCMDeployment
                

                If ($WordToComplete) {
                    $r.name.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r.name
                }
            }
        )]
        [string]
        $Deployment
    )
    
    Begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        $id = (Get-CCMDeployment -Name $Deployment).id

    }
    process {

        $irmParams = @{
            Uri         = "$($protocol)://$hostname/api/services/app/DeploymentPlans/Start"
            Method      = "POST"
            ContentType = "application/json"
            Body        = @{ id = "$id" } | ConvertTo-Json
            WebSession  = $Session
        }

        try {
            $null = Invoke-RestMethod @irmParams -ErrorAction Stop
        }
        catch {
            throw $_.Exception.Message
        }
        
    }

}
function Stop-CCMDeployment {
    <#
    .SYNOPSIS
    Stops a running CCM Deployment
     
    .DESCRIPTION
    Stops a deployment current running in Central Management
     
    .PARAMETER Deployment
    The deployment to Stop
     
    .EXAMPLE
    Stop-CCMDeployment -Deployment 'Upgrade VLC'
     
    #>

    [cmdletBinding(ConfirmImpact = "high", SupportsShouldProcess,HelpUri="https://chocolatey.org/docs/stop-ccmdeployment")]
    param(
        [ArgumentCompleter(
            {
                param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParams)
                $r = (Get-CCMDeployment).Name
                

                If ($WordToComplete) {
                    $r.Where{ $_ -match "^$WordToComplete" }
                }

                Else {

                    $r
                }
            }
        )]
        [string]
        $Deployment
    )
    begin {
        if(-not $Session){
            throw "Not authenticated! Please run Connect-CCMServer first!"
        }
        $deployId = Get-CCMDeployment -Name $Deployment | Select-Object -ExpandProperty Id
    }
    process {
    
        if ($PSCmdlet.ShouldProcess("$Deployment", "CANCEL")) {
            $irmParams = @{
                Uri         = "$($protocol)://$hostname/api/services/app/DeploymentPlans/Cancel"
                Method      = "POST"
                ContentType = "application/json"
                Body        = @{ id = "$deployId" } | ConvertTo-Json
                Websession  = $Session
            }

            try {
                $null = Invoke-RestMethod @irmParams -ErrorAction Stop
            }
            catch {
                throw $_.Exception.Message
            }
        }
    }
}