Demo-IntuneRemediation.ps1


<#PSScriptInfo
 
.VERSION 1.0.0.0
 
.GUID 618b8639-5390-4173-8967-439c47000b90
 
.AUTHOR Frits van Drie
 
.COMPANYNAME 3-Link Opleidingen (3-link.nl)
 
.COPYRIGHT (c) 2023 3-Link bv (NL). Anyone is free to use and distribute this module freely without modification. If you like this or experience failures, please notify me
 
.TAGS Demoscript
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES microsoft.graph.authentication
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES 1.0.0.0 (2024-09-06) Initial release
 
.PRIVATEDATA
 
#>



<#
 
.DESCRIPTION
    Developed by 3-Link Opleidingen for training purposes only
 
.NOTES
    Filename: Demo-IntuneRemediation
    Date: 2024-05-29
    Author: Frits van Drie (3-Link.nl)
 
    Remarks: Codesigning certificate for current User needed
 
    Version history:
        1.0.0 2024-05-25 Initial release
 
    URL: start 'https://intune.microsoft.com/#view/Microsoft_Intune_DeviceSettings/TenantAdminConnectorsMenu/~/windowsDataConnector'
    URL: https://techcommunity.microsoft.com/t5/intune-customer-success/adding-a-certificate-to-trusted-publishers-using-microsoft/ba-p/1974488
#>
 

Param()



Write-Warning 'This script is developed for demonstration. Open it in your code editor and run in step-by-step'
#Read-Host "press [Enter] to continue"

$scriptDetection   = @'
# Demo Intune detection script
 
$key = 'HKLM:\SOFTWARE\Demo'
 
try {
    Get-Item $key -ErrorAction Stop
    Write-EventLog -LogName 'Windows PowerShell' -Source ‘powershell’ -EntryType SuccessAudit -EventId 999 -Message "Intune detection: key is present ($key)"
 
    Exit 0
}
catch {
    Write-EventLog -LogName 'Windows PowerShell' -Source ‘powershell’ -EntryType Error -EventId 666 -Message "Intune detection: key not found ($key)"
    Exit 1
}
'@

$scriptRemediation = @'
# Demo Intune remediation script
 
$key = 'HKLM:\SOFTWARE\Demo'
 
try {
    New-Item $key -force -ErrorAction Stop
 
    Write-EventLog -LogName 'Windows PowerShell' -Source ‘powershell’ -EntryType SuccessAudit -EventId 999 -Message "Intune remediation: key successfully created ($key)"
    Exit 0
}
catch {
    Write-EventLog -LogName 'Windows PowerShell' -Source ‘powershell’ -EntryType Error -EventId 666 -Message "Intune detection: failed to create key ($key)"
    Exit 1
}
'@



#region: Functions

    Function GetCodeSignCertificate {
        [CmdletBinding()]

        $FunctionError    = $false

        $sourceStoreScope = 'CurrentUser'
        $sourceStorename  = 'My'
        $DestStoreScope   = 'CurrentUser'
 


        $sourceStore = New-Object  -TypeName System.Security.Cryptography.X509Certificates.X509Store  -ArgumentList $sourceStorename, $sourceStoreScope
        $sourceStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)
 
        $CertList = ($sourceStore.Certificates | Where-Object  -FilterScript {
            $_.EnhancedKeyUsageList.FriendlyName -eq 'Code Signing' -and
            (Get-Date) -ge ($_.NotBefore) -and
            (Get-Date) -le ($_.NotAfter)
        })

        $Cert = $empty
        if ($CertList) {
            $Cert = $CertList[0]
            Write-Host "Found Codesigning certificate issued by: $($cert.IssuerName.Name)" -ForegroundColor Green
        }

        if (!$Cert) {
            Write-Host "No valid Codesigning Certificate found"
            try {
                Write-Host "Creating Selfsigned Codesigning Certificate"
                $Cert = New-SelfSignedCertificate -CertStoreLocation 'Cert:\CurrentUser\My' -Type CodeSigningCert -Subject "Demo Code Signing" -FriendlyName "Demo Code Signing" -ErrorAction Stop
                Write-Host "Created Codesigning certificate issued by: $($cert.IssuerName.Name)" -ForegroundColor Green
            }
            catch {
                Write-Warning "Could not create Codesigning certificate; Process Halted."
                Return
            }
        }



        # Add Cert to Trusted Root CA store
        $DestStoreName = 'Root'
        if ($Cert.Verify()) {
            Write-Host "$($Cert.issuerName.Name) already is a Trusted Root Certification Authority" -ForegroundColor Green
        }
        else {
            Write-Host "Adding `'$($cert.IssuerName.Name)`' to $DestStoreScope\$DestStoreName"
            $FunctionError = $false
            try {
                $DestStore = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store  -ArgumentList $DestStoreName, $DestStoreScope
                $DestStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
                $DestStore.Add($cert)
                Write-Host "$($Cert.issuerName.Name) is added to Trusted Root Certification Authorities" -ForegroundColor Green
            }
            catch {
                Write-Warning "Could not copy certificate to Trusted Root Certification Authorities store"
                $FunctionError = $true
            } 
            $sourceStore.Close()
            $DestStore.Close()
        }



        # Add Cert to Trusted Publishers store
        $DestStoreName = 'TrustedPublisher'
        Write-Host "Adding `'$($cert.IssuerName.Name)`' to $DestStoreScope\$DestStoreName"
        Write-Warning "A dialog box for confirmation might be hidden behind this windows"
        try {
            $DestStore = New-Object  -TypeName System.Security.Cryptography.X509Certificates.X509Store  -ArgumentList $DestStoreName, $DestStoreScope
            $DestStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
            $DestStore.Add($cert)
        }
        catch {
            Write-Warning "Could not copy certificate to Trusted Publishers store"
            $FunctionError = $true
        } 
        $sourceStore.Close()
        $DestStore.Close()

    
        if (!$FunctionError) {
            return $Cert
        }  

    }
    Function Sign-Script {
        [CmdletBinding()]
        PARAM(
            [Parameter(Mandatory,
                       ValueFromPipeline)]
            [ValidateScript({Test-Path $_ -PathType Leaf})]
            [string]$Path,
            [Parameter(Mandatory)]
            $Certificate
        )

        if (!$Certificate) {
            throw "Error: no codesigning certificate found"
        }

        try {
            Write-Verbose "Signing `'$Path`'"
            Write-Verbose "`tCodesigning certificate thumbprint: $($Certificate.Thumbprint)"
            Set-AuthenticodeSignature -FilePath $Path -Certificate $Certificate -ErrorAction Stop|Out-Null
            Return
        }
        catch {
            throw "Error signing `'$Path`' using Codesigning certificate with thumbprint: $($Certificate.Thumbprint)"
        }
    }

#endregion: Functions

#region: Connections

    $scopes = 'DeviceManagementConfiguration.ReadWrite.All', 'Group.Read.All'
    Write-Host "Scopes: $($scopes -join ", ")"
    Write-Host "Connecting to MSGraph`t" -NoNewline
    try {
        Connect-MgGraph -Scopes $scopes -NoWelcome -ErrorAction Stop
        Write-Host "Success" -f Green
    }
    catch {
        Write-Host "Failed" -f Red
        throw $_
    }

#endregion

Clear-Host

#region: Requirements

    # enable Windows license verification
    start 'https://intune.microsoft.com/#view/Microsoft_Intune_DeviceSettings/TenantAdminConnectorsMenu/~/windowsDataConnector'

#endregion

#region: Setup Demofiles
    Write-Host "Setting-up Demo:" -ForegroundColor White

    $topic      = 'DemoIntuneRemediation'
    $folderPath = "C:\$topic"

    $folderPath | Foreach {
        $folder = $_
        if (!(Test-Path $_)) {
            try {
                New-Item $folder -ItemType Directory -ErrorAction Stop |Out-Null
                Write-Host "Folder created: $folder" -ForegroundColor Green
                Return
            }
            catch {
                Write-Warning "Error creating Folder: $folder"
                BREAK
            }
        }
        Write-Host "Folder exists: $folder" -ForegroundColor Green
    }

    Set-Location $folderPath

    try {
        $scriptDetection   | Out-File "$folderPath\Detect_$topic.ps1"    -Encoding utf8 -ErrorAction Stop
        $scriptRemediation | Out-File "$folderPath\Remediate_$topic.ps1" -Encoding utf8 -ErrorAction Stop

        Write-Host "Scripts created in folder: $folderPath" -ForegroundColor Green
    }
    catch  {
        Write-Warning "Could not write Demo files to $folderPath Check permissions."
        BREAK
    }


#endregion: Setup Demo

#region: Sign scripts

    # Codesigning Certificate
    Remove-Variable CodeSigningCertificate -ErrorAction SilentlyContinue
    $CodeSigningCertificate = GetCodeSignCertificate
    if (!$CodeSigningCertificate) {
        Write-Warning "No CodeSigning Certificate found; Script terminated."
        BREAK
    }

    $allFiles = Get-ChildItem -Path $folderPath

    ForEach ($fullName in ($allFiles).FullName) {
        try {
            Sign-Script -Path $fullName -Certificate $CodeSigningCertificate -ErrorAction Stop
            Write-Host "$fullName is signed" -ForegroundColor Green
        }
        catch {
            Write-Error "Error signing $fullName"
        }
    }


#endregion: Sign script

#region: CodeSigning certificate
    $objCert = Get-ChildItem 'Cert:\currentUser\My' | Where {$_.EnhancedKeyUsageList.FriendlyName -eq 'Code Signing'} # | Out-GridView -OutputMode Single


    ## Access the X509ChainElement objects representing each certificate in the chain
    $x509Chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
    $x509Chain.Build($objCert)
    Write-Host "Certificate chain"
    $indent=''
    foreach ($chainElement in $x509Chain.ChainElements) {
        $objElement = $chainElement.Certificate
        if ($objElement.Subject -eq $objElement.Issuer) {
           $certIssuer = 'SelfSigned'
        }
        else {
            $certIssuer = $objElement.Issuer
        }
        Write-Host "$($indent)Subject: $($objCert.Subject)" -f Yellow
        Write-Host "$($indent)`tThumbprint : $($objElement.Thumbprint)"
        Write-Host "$($indent)`tHasPrivateKey: $($objElement.HasPrivateKey)"
        Write-Host "$($indent)`tIssuer : $($certIssuer)"
        $indent += "`t"
        #Write-Host "`n"
    }

#endregion