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 |