Driver.Firmware.Servicing.psm1

#Region '.\Private\Invoke-GetRequest.ps1' 0
function Invoke-GetRequest {
    <#
    .SYNOPSIS
        Performs Get Requests with Pagination.
    .DESCRIPTION
        Performs Get Requests with Pagination. Without the logic in this function, all results would not be returned.
    .NOTES
        Tested on PowerShell 5 and 7 on Windows.
    .EXAMPLE
        Invoke-GetRequest -Uri "https://graph.microsoft.com/beta/me"
        Invoke-GetRequest -Uri "https://graph.microsoft.com/beta/me" -All
    .PARAMETER Uri
        The URI to perform the Get Request on. This is a mandatory parameter.
    .PARAMETER All
        This switch will determine if paginated requests will be run. This is an optional parameter.
    #>

    [CmdletBinding()]
    param (
        # Parameter help description
        [Parameter(Mandatory = $true)]
        [string]
        $Uri,
        # This switch will determine if paginated requests will be run
        [switch]
        $All
    )
    process {
        switch ($All) {
            true {
                $getRequestParameters = @{
                    Method = "GET"
                    URI    = $Uri
                }

                $getRequest = Invoke-MgGraphRequest @getRequestParameters -ErrorAction Stop
                $requestArray = @()
                $requestArray += IF ($getRequest.value) { $getRequest.value }else { $getRequest }
                while ($getRequest.'@odata.nextLink') {
                    $getRequest_NextLink = @{
                        Method = "GET"
                        URI    = $getRequest.'@odata.nextLink'
                    }
                    $getRequest = Invoke-MgGraphRequest @getRequest_NextLink -ErrorAction Stop
                    $requestArray += IF ($getRequest.value) { $getRequest.value }else { $getRequest }
                }

                $return = $requestArray
            }
            false {
                $getRequestParameters = @{
                    Method = "GET"
                    URI    = $Uri
                }
                $return = (Invoke-MgGraphRequest @getRequestParameters -ErrorAction Stop).value
            }
        }
    }
    end {
        return $return
    }
}
#EndRegion '.\Private\Invoke-GetRequest.ps1' 62
#Region '.\Public\Add-DriverUpdatePolicyAudienceMember.ps1' 0
function Add-DriverUpdatePolicyAudienceMember {
    <#
    .SYNOPSIS
        Add members to a deployment audience for Windows Updates for Business
    .DESCRIPTION
        This function will check if the deployments audiences have the devices as members, and if not they will be added to the audience.
    .EXAMPLE
        Add-DriverUpdatePolicyAudienceMember -azureDeviceIDs ("ID1","ID2") -updateAudienceID <AudienceID>
    .PARAMETER azureDeviceIDs
        The Azure Device IDs to add to the audience.
    .PARAMETER updateAudienceID
        The Update Audience ID to add the members to.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [array]
        $azureDeviceIDs,
        # The Update Audience ID
        [Parameter(Mandatory = $true)]
        [string]
        $updateAudienceID

    )
    begin {
        # Create the param body base
        $paramBody = @{
            addMembers = @(
            )
        }
    }
    process {
        $updateAudienceMembers = Get-DriverUpdatePolicyAudienceMember -policyID $updateAudienceID
        foreach ($id in $azureDeviceIDs) {
            IF (-Not($updateAudienceMembers.id -contains $id)) {
                $memberObject = @{
                    "@odata.type" = "#microsoft.graph.windowsUpdates.azureADDevice"
                    id            = $id
                }
                $paramBody.addMembers += $memberObject
            }
        }
    }
    end {
        IF ($paramBody.addMembers.Count -ge 1) {
            Invoke-MgGraphRequest `
                -Method POST `
                -Uri "https://graph.microsoft.com/beta/admin/windows/updates/deploymentAudiences('$updateAudienceID')/updateAudience" `
                -Body $paramBody
        }
    }
}
#EndRegion '.\Public\Add-DriverUpdatePolicyAudienceMember.ps1' 53
#Region '.\Public\Get-DriverUpdateDeploymentAudience.ps1' 0
function Get-DriverUpdateDeploymentAudience {
    <#
    .SYNOPSIS
        This function get Update Deployment Audiences.
    .DESCRIPTION
        This function get Update Deployment Audiences.
    .NOTES
        This has only been tested for the commercial driver and firmware updates.
    .EXAMPLE
        Get-DriverUpdateDeploymentAudience
        Get-DriverUpdateDeploymentAudience -audienceID <audienceID>
    .PARAMETER audienceID
        The audience ID to get the deployment audience for.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [string]
        $audienceID
    )
    process {
        try {
            IF ([string]::IsNullOrEmpty($audienceID)) {
                $DriverUpdateDeploymentAudience = Invoke-GetRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/deploymentAudiences" -All
            }
            elseif (-Not([string]::IsNullOrEmpty($audienceID))) {
                $DriverUpdateDeploymentAudience = Invoke-GetRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/deploymentAudiences?`$filter=id eq '$audienceID'"
            }
        }
        catch {
            throw "Unable to get the deployment audiences. $($_.Exception.Message)"
        }
    }
    end {
        return $DriverUpdateDeploymentAudience
    }
}
#EndRegion '.\Public\Get-DriverUpdateDeploymentAudience.ps1' 38
#Region '.\Public\Get-DriverUpdatePolicy.ps1' 0
function Get-DriverUpdatePolicy{
    <#
.SYNOPSIS
    This function gets all update policies for Windows Updates for Business for Driver and Firmware Servicing.
.DESCRIPTION
    This function gets all update policies for Windows Updates for Business for Driver and Firmware Servicing.
.NOTES
    This has only been tested for the commercial driver and firmware updates.
    https://learn.microsoft.com/en-us/graph/api/adminwindowsupdates-list-updatepolicies?view=graph-rest-beta&tabs=http
.EXAMPLE
    Get-DriverUpdatePolicy
.PARAMETER policyID
    The policy ID to get. If not specified, all policies will be returned.
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [string]
        $policyID
    )
    process {
        try {
            IF([string]::IsNullOrEmpty($policyID)){
                $policy = Invoke-GetRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/updatePolicies" -All
            } elseif (-Not([string]::IsNullOrEmpty($AzureADDeviceID))) {
                $policy = Invoke-GetRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/updatePolicies?`$filter=id eq '$policyID'"
            }
        }
        catch {
            throw "Unable to get the policies. $($_.Exception.Message)"
        }
    }
    end {
        return $policy
    }
}
#EndRegion '.\Public\Get-DriverUpdatePolicy.ps1' 37
#Region '.\Public\Get-DriverUpdatePolicyApplicableContent.ps1' 0
function Get-DriverUpdatePolicyApplicableContent {
    <#
.SYNOPSIS
    This function will get the deployable content of a deployment audience based on a PolicyID for Windows Updates for Business.
.DESCRIPTION
    This function will get the deployable content of a deployment audience based on a PolicyID for Windows Updates for Business.
.NOTES
    This has only been tested for the commercial driver and firmware updates.
.EXAMPLE
    Get-DriverUpdatePolicyApplicableContent -policyID <PolicyID>
.PARAMETER policyID
    The policy ID to get the applicable content for.
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]
        $policyID
    )
    process {
        try {
            $policy = Get-DriverUpdatePolicy -policyID $policyID
            $applicableConent = Invoke-GetRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/deploymentAudiences('$($policy.audience.id)')/applicableContent?`$expand=catalogEntry" -All
        }
        catch {
            throw "Unable to get the applicable content of the deployment audience. $($_.Exception.Message)"
        }
    }
    end {
        return $applicableConent
    }
}
#EndRegion '.\Public\Get-DriverUpdatePolicyApplicableContent.ps1' 33
#Region '.\Public\Get-DriverUpdatePolicyAudienceMember.ps1' 0
function Get-DriverUpdatePolicyAudienceMember {
    <#
.SYNOPSIS
    This function will get the members of a deployment audience for Windows Updates for Business.
.DESCRIPTION
    This function will get the members of a deployment audience for Windows Updates for Business.
.NOTES
    This has only been tested for the commercial driver and firmware updates.
.EXAMPLE
    Get-DriverUpdatePolicyAudienceMember -policyID <PolicyID>
.PARAMETER policyID
    The policy ID to get the members for.
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]
        $policyID
    )
    process {
        try {
            $policy = Get-DriverUpdatePolicy -policyID $policyID
            $members = Invoke-GetRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/deploymentAudiences('$($policy.audience.id)')/members" -All
        }
        catch {
            throw "Unable to get the members of the deployment audience. $($_.Exception.Message)"
        }
    }
    end {
        return $members
    }
}
#EndRegion '.\Public\Get-DriverUpdatePolicyAudienceMember.ps1' 33
#Region '.\Public\Get-UpdatableAsset.ps1' 0
function Get-UpdatableAsset {
    <#
    .SYNOPSIS
        This function get all updateable assets for Windows Updates for Business.
    .DESCRIPTION
        This function get all updateable assets for Windows Updates for Business.
    .NOTES
        This has only been tested for the commercial driver and firmware updates.
    .EXAMPLE
        Get-UpdatableAsset
        Get-UpdatableAsset -AzureADDeviceID <AzureADDeviceID>
    .PARAMETER AzureADDeviceID
        The Azure AD Device ID to get the updatable asset for.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [string]
        $AzureADDeviceID
    )
    process {
        try {
            IF ([string]::IsNullOrEmpty($AzureADDeviceID)) {
                $updatableAsset = Invoke-GetRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/updatableAssets" -All
            }
            elseif (-Not([string]::IsNullOrEmpty($AzureADDeviceID))) {
                $updatableAsset = Invoke-GetRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/updatableAssets?`$filter=id eq '$AzureADDeviceID'"
            }
        }
        catch {
            throw "Unable to get the updatable assets. $($_.Exception.Message)"
        }
    }
    end {
        return $updatableAsset
    }
}
#EndRegion '.\Public\Get-UpdatableAsset.ps1' 38
#Region '.\Public\New-DriverUpdateDeploymentAudience.ps1' 0
function New-DriverUpdateDeploymentAudience {
    <#
    .SYNOPSIS
        Creates a WUfBDS Deployment Audience
    .DESCRIPTION
        Creates a WUfBDS Deployment Audience for Policy Assignment.
    .EXAMPLE
        New-DriverUpdateDeploymentAudience
    .PARAMETER daAudienceParams
        The parameters to create the deployment audience.
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        $daAudienceParams = @{}
    )
    process {

        if ($pscmdlet.ShouldProcess(
            'Creating a WUfBDS Deployment Audience',
            'Warning: Creating a WUfBDS Deployment Audience',
            'Question: Are you sure you want to do continue?'))
        {
            $daAudience = Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/deploymentAudiences" -Method POST -Body $daAudienceParams
        }
    }
    end {
        return $daAudience
    }
}
#EndRegion '.\Public\New-DriverUpdateDeploymentAudience.ps1' 30
#Region '.\Public\New-DriverUpdatePolicy.ps1' 0
function New-DriverUpdatePolicy {
    <#
    .SYNOPSIS
        This function is to be used to create a Driver Policy for WUfBDS
    .DESCRIPTION
        Based on the inputs, will depend on the policy creation type of Manual or Automatic.
    .EXAMPLE
        New-DriverUpdatePolicy -deploymentAudienceID $daAudience.id -policyType Automatic -deferralTime PT1D
    .PARAMETER deploymentAudienceID
        The Deployment Audience ID. This can be obtained from the Get-DriverUpdateDeploymentAudience function.
    .PARAMETER policyType
        The type of policy to create. Manual or Automatic.
    .PARAMETER deferralTime
        The deferral time for the policy. This is only required for Automatic policies.
    #>

    [CmdletBinding(SupportsShouldProcess=$true)]
    param (
        # The Deployment Audience ID
        [Parameter(Mandatory = $true)]
        [string]
        $deploymentAudienceID,
        # Manual or Automatic Publishing Policy
        [Parameter(Mandatory = $true)]
        [ValidateSet("Manual", "Automatic")]
        [string]
        $policyType,
        # ISO8601 Timeformat for Deferral
        [Parameter()]
        [string]
        $deferralTime = "PT0S"
    )
    begin {
        #Initialise the base object body.
        $paramBody = @{
            "@odata.type"                  = "#microsoft.graph.windowsUpdates.updatePolicy"
            audience                       = @{
                id = $deploymentAudienceID
            }
            autoEnrollmentUpdateCategories = @(
                "driver"
            )
        }
    }
    process {
        switch ($policyType) {
            Manual {
                $paramBody.deploymentSettings = @{
                    schedule             = $null
                    monitoring           = $null
                    contentApplicability = $null
                    userExperience       = $null
                    expedite             = $null
                }
            }
            Automatic {

                $paramBody.deploymentSettings = @{
                    schedule             = $null
                    monitoring           = $null
                    contentApplicability = @{
                        offerWhileRecommendedBy = @(
                            "microsoft"
                        )
                        safeguard               = $null
                    }
                    userExperience       = $null
                    expedite             = $null
                }
                $paramBody.complianceChangeRules = @(
                    @{
                        "@odata.type"                 = "#microsoft.graph.windowsUpdates.contentApprovalRule"
                        durationBeforeDeploymentStart = $deferralTime
                        contentFilter                 = @{
                            "@odata.type" = "#microsoft.graph.windowsUpdates.driverUpdateFilter"
                        }
                    }
                )
            }
        }
    }
    end {
        if ($PSCmdlet.ShouldProcess(
                'Creating a WUfBDS Driver Update Policy',
                'Warning: Creating a WUfBDS Driver Update Policy',
                'Question: Are you sure you want to do continue?')) {
            Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/updatePolicies"`
                -Method POST `
                -Body $paramBody `
                -ContentType 'application/json'
        }
    }
}
#EndRegion '.\Public\New-DriverUpdatePolicy.ps1' 93
#Region '.\Public\Push-EnrollUpdateableAsset.ps1' 0
function Push-EnrollUpdateableAsset {
    <#
    .SYNOPSIS
        This script is to be used to push enrol assets as without it, the delay could be significant.
    .DESCRIPTION
        This script is to be used to push enrol assets as without it, the delay could be significant.
    .NOTES
        This has only been tested for the commercial driver and firmware updates.
    .EXAMPLE
        Push-EnrollUpdateableAsset -azureDeviceIDs ('ID1','ID2')
    .PARAMETER azureDeviceIDs
        The Azure AD Device IDs to enroll as updateable assets.
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        [Parameter(Mandatory = $true)]
        [array]
        $azureDeviceIDs
    )
    begin {
        # Create the param body base
        $paramBody = @{
            updateCategory = "driver"
            assets         = @(
            )
        }
    }
    process {
        if($PSCmdlet.ShouldProcess("Enroll Assets", "Enroll Assets")) {
            $updateAudienceMembers = Get-DriverUpdatePolicyAudienceMember -policyID $updateAudienceID
            foreach ($id in $azureDeviceIDs) {
                IF (-Not($updateAudienceMembers.id -contains $id)) {
                    $memberObject = @{
                        "@odata.type" = "#microsoft.graph.windowsUpdates.azureADDevice"
                        id            = $id
                    }
                    $paramBody.addMembers += $memberObject
                }
            }
        }
        $updatableAssets = Get-UpdatableAsset
        foreach ($id in $azureDeviceIDs) {
            IF (-Not($updatableAssets | Where-Object { $_.id -match $id }).enrollments.updateCategory -notcontains "driver") {
                $memberObject = @{
                    "@odata.type" = "#microsoft.graph.windowsUpdates.azureADDevice"
                    id            = $id
                }
                $paramBody.assets += $memberObject
            }
        }
    }
    end {
        IF ($paramBody.assets.Count -ge 1) {
            Invoke-MgGraphRequest `
                -Method POST `
                -Uri "https://graph.microsoft.com/beta/admin/windows/updates/updatableAssets/enrollAssets" `
                -Body $paramBody
        }
    }
}
#EndRegion '.\Public\Push-EnrollUpdateableAsset.ps1' 61
#Region '.\Public\Remove-DriverUpdatePolicyAudienceMember.ps1' 0
function Remove-DriverUpdatePolicyAudienceMember {
    <#
    .SYNOPSIS
        Remove members from a deployment audience for Windows Updates for Business
    .DESCRIPTION
        This function will check if the deployments audiences have the devices as members, and if so they will be removed from the audience.
    .EXAMPLE
        Remove-DriverUpdatePolicyAudienceMember -azureDeviceIDs ("ID1","ID2") -updateAudienceID <AudienceID>
    .PARAMETER azureDeviceIDs
        The Azure Device IDs to add to the audience.
    .PARAMETER policyID
        The Update Policy ID to get the audience from.
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        [Parameter(Mandatory = $true)]
        [array]
        $azureDeviceIDs,
        # The Update Audience ID
        [Parameter(Mandatory = $true)]
        [string]
        $policyID

    )
    begin {
        # Create the param body base
        $paramBody = @{
            removeMembers = @(
            )
        }
    }
    process {
        if ($PSCmdlet.ShouldProcess("Remove members from the deployment audience")) {
            Write-Verbose "Removing members from the deployment audience"
        }
        else {
            return
        }
        $updateAudienceID = (Get-DriverUpdatePolicy -policyID $policyID).audience.id
        $updateAudienceMembers = Get-DriverUpdatePolicyAudienceMember -policyID $policyID
        foreach ($id in $azureDeviceIDs) {
            IF ($updateAudienceMembers.id -contains $id) {
                $memberObject = @{
                    "@odata.type" = "#microsoft.graph.windowsUpdates.azureADDevice"
                    id            = $id
                }
                $paramBody.removeMembers += $memberObject
            }
        }
    }
    end {
        IF ($paramBody.removeMembers.Count -ge 1) {
            Invoke-MgGraphRequest `
                -Method Post `
                -Uri "https://graph.microsoft.com/beta/admin/windows/updates/deploymentAudiences('$updateAudienceID')/updateAudience" `
                -Body $paramBody
        }
    }
}
#EndRegion '.\Public\Remove-DriverUpdatePolicyAudienceMember.ps1' 60
#Region '.\Public\Update-DriverUpdatePatchDeferral.ps1' 0
function Update-DriverUpdatePatchDeferral {
    <#
    .SYNOPSIS
        This function is to be used to update the Patch Deferral on Update Policies.
    .DESCRIPTION
        This function is to be used to update the Patch Deferral on Update Policies.
    .NOTES
        This has only been tested for the commercial driver and firmware updates.
    .EXAMPLE
        Update-DriverUpdatePatchDeferral -policyID <id> -deferralTime P1D
        Explanation of the function or its result. You can include multiple The deferral time must be in the ISO8601 format.
    .PARAMETER policyID
        The Update Policy ID. You can get this from the Get-DriverUpdatePolicy function.
    .PARAMETER deferralTime
        The deferral time must be in the ISO8601 format.
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        # The Update Policy ID
        [Parameter(Mandatory = $true)]
        [string]
        $policyID,
        # ISO8601 Timeformat for Deferral
        [Parameter(Mandatory = $true)]
        [string]
        $deferralTime
    )
    begin {
        #The Base Object for the post Body
        $paramBody = @{
            "@odata.type"         = "#microsoft.graph.windowsUpdates.updatePolicy"
            complianceChangeRules = @()
        }
        # Create the param body base
        $complianceChangeRules = (Get-DriverUpdatePolicy -policyID $policyID).complianceChangeRules
    }
    process {
        $paramBody.complianceChangeRules += $complianceChangeRules
        $paramBody.complianceChangeRules | foreach-object {
            $_.durationBeforeDeploymentStart = $deferralTime
        }
        $deferralTime | Out-Null #Adding in this line to stop the output of the deferral time
    }
    end {
        Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/beta/admin/windows/updates/updatePolicies/$policyID" -Method PATCH -Body $paramBody
    }
}
#EndRegion '.\Public\Update-DriverUpdatePatchDeferral.ps1' 48