Demo-ExecutionPolicy.ps1


<#PSScriptInfo
 
.VERSION 1.0.0
 
.GUID 983cad9d-a754-4664-9650-4e5adba88269
 
.AUTHOR Frits van Drie (3-Link.nl)
 
.COMPANYNAME 3-Link Opleidingen
 
.COPYRIGHT free to use and distribute without modifications
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
.PRIVATEDATA
 
#>


<#
 
.DESCRIPTION
 Developed by 3-Link Opleidingen for training purposes only
 
#>
 
Param()


# Filename: Demo-ExecutionPolicy
# Date: 2022-04-07
# Author: Frits van Drie (3-Link.nl)

# Remarks: Codesigning certificate for current User needed

Write-Warning 'This script is developed for demonstration. Open it in your code editor and run in step-by-step'
BREAK

#region: Functions

    Function RetrieveCodeSignCertificate {
        [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) -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"
        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) {
            Write-Warning "Error: no codesigning certificate found"
            Throw
        }

        try {
            Write-Host "Signing `'$Path`' using Codesigning certificate with thumbprint: $($Certificate.Thumbprint)" -ForegroundColor Yellow
            Set-AuthenticodeSignature -FilePath $Path -Certificate $Certificate -ErrorAction Stop|Out-Null
            Return
        }
        catch {
            Write-Warning "Error signing `'$Path`' using Codesigning certificate with thumbprint: $($Certificate.Thumbprint)"
            Throw
        }
    }
    Function Get-ZoneIdentifier {
        [CmdletBinding()]
        PARAM(
            [Parameter(Mandatory,
                       ValueFromPipeline)]
            [ValidateScript({Test-Path $_ -PathType Leaf})]
            [string]$Path
        )

        ForEach ($FilePath in $Path) {
            try {
                Get-Content `
                    -path $FilePath `
                    -Stream Zone.Identifier `
                    -ErrorAction Stop
            }
            catch {
                Write-Warning "Could not read the alternate data stream 'Zone.Identifier' "
            }
        }
    }
    Function Set-ZoneIdentifier {
        [CmdletBinding()]
        PARAM(
            [Parameter(Mandatory,
                       ValueFromPipeline)]
            [ValidateScript({Test-Path $_ -PathType Leaf})]
            [string]$Path
        )

        ForEach ($FilePath in $Path) {
            try {
                Set-Content `
                    -path $FilePath `
                    -Stream Zone.Identifier `
                    -Value "[ZoneTransfer]
                            ZoneId=3
                            HostUrl=https://thisfile.com/es/from/remote.ps1
                    "

                Write-Verbose "Zone.Identifier written to alternate datastream of file: $FilePath" -Verbose
            }
            catch {
                Write-Verbose "Error writing alternate datastream to file: $FilePath" -Verbose
                Throw
            }
        }
    }
    Function Cleanup-DemoExecutionPolicy {
        param(
            $path
        )

            try {
                Remove-Item $path -Recurse -Confirm:$false -Force -ea Stop
                Write-Host "Removed $path" -f Green
                return
            }
            catch {

                Write-Warning $error[0].Exception.Message
            }

    }


#endregion: Functions
Clear-Host
#region: Setup Demofiles
    Write-Host "Setting-up Demo:" -ForegroundColor White
    $folderPath = 'C:\DemoExecutionPolicy\'
    #$DownloadPath = Join-Path $folderPath "Downloaded"
    #$folderPath, $DownloadPath| Foreach {
    $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 {
        "Write-Host `"This script is not signed`" -BackgroundColor Red -ForegroundColor Yellow" | Out-File (Join-Path $folderPath Unsigned.ps1)              -ErrorAction Stop
        "Write-Host `"This script is signed`" -BackgroundColor Red -ForegroundColor Yellow" | Out-File (Join-Path $folderPath Signed.ps1)                -ErrorAction Stop
        "Write-Host `"This script is downloaded and signed`" -BackgroundColor Red -ForegroundColor Yellow" | Out-File (Join-Path $folderPath RemoteSigned.ps1)          -ErrorAction Stop
        "Write-Host `"This script is downloaded and not signed`" -BackgroundColor Red -ForegroundColor Yellow" | Out-File (Join-Path $folderPath RemoteUnsigned.ps1)        -ErrorAction Stop
        "Write-Host `"This script is downloaded and unblocked`" -BackgroundColor Red -ForegroundColor Yellow" | Out-File (Join-Path $folderPath RemoteUnsignedUnBlock.ps1) -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 = RetrieveCodeSignCertificate
    if (!$CodeSigningCertificate) {
        Write-Warning "No CodeSigning Certificate found; Script terminated."
        BREAK
    }

    ForEach ($FileName in "Signed.ps1","RemoteSigned.ps1") {
        $ScriptPath = (Join-Path $folderPath $FileName)
        try {
            Sign-Script -Path $ScriptPath -Certificate $CodeSigningCertificate -ErrorAction Stop
            Write-Host "$ScriptPath is signed" -ForegroundColor Green
        }
        catch {
            Write-Error "Error signing $ScriptPath"
        }
    }


#endregion: Sign script
#region: Set Zone.Identifier
    ForEach ($FileName in "RemoteSigned.ps1", "RemoteUnsigned.ps1", "RemoteUnsignedUnblock.ps1") {
        $ScriptPath = (Join-Path $folderPath $FileName)
        try {
            Set-ZoneIdentifier -Path $ScriptPath -Verbose
        }
        catch {
            Write-Warning "Error writing alternate datastream to file: $ScriptPath"
        }
    }
#endregion: Set Zone.Identifier

$execPol = Get-ExecutionPolicy  # save current setting




BREAK

#region: Demo ExecutionPolicy



    Set-ExecutionPolicy Undefined
    Get-ExecutionPolicy               #==> Restricted
    .\Unsigned.ps1                    #==> unsigned.ps1 cannot be loaded because running scripts is disabled on this system
    .\Signed.ps1                      #==> signed.ps1 cannot be loaded because running scripts is disabled on this system



    Set-ExecutionPolicy Restricted -Force
    Get-ExecutionPolicy               #==> Restricted
    .\Unsigned.ps1                    #==> unsigned.ps1 cannot be loaded because running scripts is disabled on this system
    .\Signed.ps1                      #==> signed.ps1 cannot be loaded because running scripts is disabled on this system



    Set-ExecutionPolicy AllSigned -Force
    Get-ExecutionPolicy               #==> AllSigned
    .\Unsigned.ps1                    #==> unsigned.ps1 is not digitally signed
    .\Signed.ps1                      # [R] Run once

    gci Cert:\CurrentUser\TrustedPublisher -CodeSigningCert

    Set-ExecutionPolicy Bypass -Force
    Get-ExecutionPolicy               #==> Bypass
    .\Unsigned.ps1                    #==> Script runs
    .\Signed.ps1                      #==> Script runs



    Set-ExecutionPolicy RemoteSigned -Force
    Get-ExecutionPolicy               #==> RemoteSigned
    .\Unsigned.ps1                    #==> Script runs
    .\Signed.ps1                      #==> Script runs
    .\RemoteSigned.ps1                #==> Script runs
    .\RemoteSigned.ps1                #==> remoteSigned.ps1 is modified and falsely signed
    .\RemoteUnsigned.ps1              #==> remoteunsigned.ps1 is downloaded and not digitally signed
    .\RemoteUnsignedUnblock.ps1       #==> remoteunsignedunblock.ps1 is downloaded and not digitally signed

    Get-Content .\RemoteUnsignedUnblock.ps1 -Stream zone.identifier
    Unblock-File .\RemoteUnsignedUnblock.ps1
    .\RemoteUnsignedUnblock.ps1       #==> Script runs


    # Modify a signed script
    .\RemoteSigned.ps1                #==> Script runs
    Get-FileHash .\RemoteSigned.ps1
    (Get-Content .\RemoteSigned.ps1).Length #==> 34 lines
    ((Get-Content .\RemoteSigned.ps1).GetEnumerator().length |measure -Sum).Sum #==> 2082 characters
    "" | Out-File .\RemoteSigned.ps1 -Append
    (Get-Content .\RemoteSigned.ps1).Length #==> 35 lines
    Get-FileHash .\RemoteSigned.ps1
    .\RemoteSigned.ps1                #==> remoteSigned.ps1 is modified and falsely signed



#endregion: Demo ExecutionPolicy




BREAK

 #region: Cleanup Demo

    Set-ExecutionPolicy byPass -Force
    Set-Location C:\

    # Certificates
    Cleanup-DemoExecutionPolicy -path "Cert:\CurrentUser\My\$($CodeSigningCertificate.Thumbprint)"
    Cleanup-DemoExecutionPolicy -path "Cert:\CurrentUser\Root\$($CodeSigningCertificate.Thumbprint)"
    Cleanup-DemoExecutionPolicy -path "Cert:\CurrentUser\TrustedPublisher\$($CodeSigningCertificate.Thumbprint)"

    # Files
    Cleanup-DemoExecutionPolicy -path $folderPath

    # Set ExecutionPolicy to saved setting
    Set-ExecutionPolicy $execPol -Force

    # Variables
    'ExecPol', 'FileName', 'folderpath', 'ScriptPath' | Foreach {
        Cleanup-DemoExecutionPolicy -path VARIABLE:\$_
    }

    # Functions
    Cleanup-DemoExecutionPolicy -path "Function:\RetrieveCodeSignCertificate"
    Cleanup-DemoExecutionPolicy -path "Function:\Sign-Script"
    Cleanup-DemoExecutionPolicy -path "Function:\Get-ZoneIdentifier"
    Cleanup-DemoExecutionPolicy -path "Function:\Set-ZoneIdentifier"

    Cleanup-DemoExecutionPolicy -path "Function:\Cleanup-DemoExecutionPolicy"
    


    

 #endregion




<#PSScriptInfo



.VERSION 1.0.0



.GUID 31064322-a8eb-434c-96c9-aae3b23879f2



.AUTHOR Frits van Drie (3-Link.nl)



.COMPANYNAME 3-Link Opleidingen



.COPYRIGHT free to use and distribute without modifications



.TAGS



.LICENSEURI



.PROJECTURI



.ICONURI



.EXTERNALMODULEDEPENDENCIES 



.REQUIREDSCRIPTS



.EXTERNALSCRIPTDEPENDENCIES



.RELEASENOTES





.PRIVATEDATA



#>



<# 



.DESCRIPTION 

 Developed by 3-Link Opleidingen for training purposes only 



#> 

Param()