Font size: +
5 minutes reading time (1018 words)

PowerShell Sign Code And Upload In The PowerShell Gallery

PowerShell_Pix

PowerShell_sign_code_and_upload_in_the_PowerShell galleryPowerShell_sign_code_and_upload_in_the_PowerShell galleryLast friday at the PowerShell Usergroup Hannover I briefly talked about CodeSigning for PowerShell modules for upload to the PowerShell Gallery. Well, the interest of my colleagues was bigger than expected and also some questions remained unanswered. Here also some things have changed. Fact is, most modules in the Gallery are unsigned. In the end, the question always arises, why sign at all, when the PowerShell execution policy can be so easily overridden?For example it is possible to execute arbitrary code with

Powershell.exe -ExecutionPolicy Bypass -File <PathToPowershellSkript.ps1>.

I have been using code signing certificates for my community PowerShell scripts for several years. This is especially well received by our customers. Our work is digitally signed with it. Furthermore the inhibitions are a little bit bigger to change scripts later because the signature block always has to be changed.

Simple code signature certificates are available for three years under 200€ (if you are looking for something).  With this certificate it is easy to sign your scripts. The certificate can be found after a correct import into your own CertStore:

 MMC Certificates


With the PowerShell you can display your own certificates via Get-ChildItem.

Get-ChildItem Cert:\CurrentUser\My

Thumbprint with PowerShell

The certificate is identified by the propertie "Thrumbprint". This can also be viewed in the properties of the certificate.

Certificate Properties Thumb

The certificate for the signing process can be read out via PowerShell. The thumbprint serves as access key:he certificate for the signing process can be read out via PowerShell. The thumbprint serves as access key:

$cert = @(Get-ChildItem Cert:\CurrentUser\my\7FB82C295C4B3DC0C3BF8C76378461E9B48186DF -codesigning)[0]

The signature with timestamp is now done

Set-AuthenticodeSignature <PathToFile.ps1>
$cert -TimestampServer http://timestamp.comodoca.com

It is important to specify the timespamp server so that your signatures are valid after the expiration date. Other CA's than Comodo have other timespamp servers hereAs a result the skript gets a signature.

# SIG # Begin signature block# 
MIIetQYJKoZIhvcNAQcCoIIepjCCHqICAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB# 
gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR# 
AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUFw86ss8Cl40CWe+LUa4iwVtD# 
Pxugghm/MIIEhDCCA2ygAwIBAgIQQhrylAmEGR9SCkvGJCanSzANBgkqhkiG9w0B
…

# SIG # End signature block

 The valid signature can be recognized via the properties of the scriptThe valid signature can be recognized via the properties of the script.

Now the PowerShell execution policy can be set to AllSigned or not? Well, the problem is, there is still a message when executing the script:
Set-ExecutionPolicy -ExecutionPolicy AlLSigned 
Now we get the following message:

Do you want to run software from this untrusted publisher? 
File C:\Users\Andreas\Desktop\test-codesigning.ps1 is published by CN=Nick Informationstechnik GmbH, O=Nick Informationstechnik GmbH... 
and is not trusted on your system. 
Only run scripts from trusted publishers.[V] Never run [D] Do not run [R] Run once [A] Always run [?] Help (default is "D"):

Well, Kamil from PSUGH knew the answer. The scripts still cannot be executed until the own certificate appears in the "Trusted Publishes" of the own certificates. If the question above is answered with [A], the PowerShell copies the certificate automatically to the correct location "Trusted Publishers". For a company it is recommended to distribute the certificates that are allowed to sign code via group policy.

22 01 2020 16 07 26

The signing of a PowerShell project can of course also be done with PowerShell via a script.The signing of a PowerShell project can of course also be done with PowerShell via a script.

$cert = @(Get-ChildItem Cert:\CurrentUser\my\7FB82C295C4B3DC0C3BF8C76378461E9B48186DF -codesigning)[0]

Get-ChildItem D:\AppVForcelets | ForEach-Object `
{  Set-AuthenticodeSignature $_.FullName $cert -TimestampServer http://timestamp.comodoca.com
}

The download Now the new, fully signed module should be published in the PowerShell gallery. Remember - packages in the PowerShell gallery can be downloaded with install modules. We recommend the switch -Scope CurrentUser. Then new modules end up under Documents\MicrosoftPowerShell\Modules and not in the system. Well, the first thing you get here is a "You are installing the modules from an untrusted repository? How? The PowerShellGallery is not trusted? But yes - everybody can upload something there and basically nobody checks the scripts. Trustworthy has nothing to do with the signature.

Untrusted Repository

The message will be lost forever:The message will be lost forever:

Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted

As said, please note that there may be some dangerous code coming over it.

The Upload

The upload to the Gallery is done with Publish-Module then -Name (module name in a module directory) or -Path for the direct path to the module. Finally the NuGetApiKey with -NuGetApiKey. You can find the key in your PowerShell Gallery account in your profile. Besides that you can enter further information. For example a URL for the license or tags.

Publish Module

This works very well as long as the script has no signature. So now we come to the core. Something has changed here. With a digital signature a catalog file (.cat) is now required. This file contains hashes for all files in a directory. This file must itself be digitally signed. Only then it works with the upload of digitally signed scripts into the PowerShell Gallery.This works very well as long as the script has no signature. So now we come to the core. Something has changed here. With a digital signature a catalog file (.cat) is now required. This file contains hashes for all files in a directory. This file must itself be digitally signed. Only then it works with the upload of digitally signed scripts into the PowerShell Gallery.For the example above these are the following instructions:

New-FileCatalog -Path D:\AppVForcelets -CatalogFilePath D:\ AppVForcelets\AppVForcelets.cat -CatalogVersion 2.0
$cert = @(Get-ChildItem Cert:\CurrentUser\my\7FB82C295C4B3DC0C3BF8C76378461E9B48186DF -codesigning)[0]
Set-AuthenticodeSignature D:\ AppVForcelets\AppVForcelets.cat $cert -TimestampServer http://timestamp.comodoca.com

There must be a valid manifest in the module itself. In particular, the version number must be increased after each upload.

# Version Number
# Version NumberModuleVersion = '1.3'.

In addition, there can be a PrivateData Blog in which information can be entered, but which can also be specified by parameters in Publish modules. For example tags or the project page.

# Private data that needs to be passed to this module
PrivateData = @{
    PSData = @{
       
        Tags = @('App-V','AppV','DeploymentConfig','AppXManifest')

        # A URL to the license for this module.
        LicenseUri = 'https://raw.githubusercontent.com/AndreasNick/AppVForcelets/master/LICENSE'
        # A URL to the main website for this project.
        ProjectUri = 'http://www.andreasnick.com'
        # A URL to an icon representing this module.
        # IconUri = ''
        # ReleaseNotes of this module
        # ReleaseNotes = ''
    } # End of PSData hashtable

} # End of PrivateData hashtable

 

 

 

PowerShell Gallery Module

 

App-V PowerShell Module AppVForcelets
App-V Registry Staging Problems With Citrix PVS (M...

Related Posts

 

Comments 1

Guest - Kevin Severud on Wednesday, January 22, 2020 18:04

Sign a folder (and subfolders, if so desired) of files and use splatting too!

$PowerShellFile = @{
Certificate = (Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert)[0]
TimestampServer = "http://timestamp.digicert.com"
HashAlgorithm = "SHA256"
}
$PowerShellScripts = @{
Path = "\\DFSshare\path"
Filter = "*.ps1"
Recurse = $true
}
Get-ChildItem @PowerShellScripts | Set-AuthenticodeSignature @PowerShellFile

Sign a folder (and subfolders, if so desired) of files and use splatting too! :D $PowerShellFile = @{ Certificate = (Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert)[0] TimestampServer = "http://timestamp.digicert.com" HashAlgorithm = "SHA256" } $PowerShellScripts = @{ Path = "\\DFSshare\path" Filter = "*.ps1" Recurse = $true } Get-ChildItem @PowerShellScripts | Set-AuthenticodeSignature @PowerShellFile
Already Registered? Login Here
Sunday, December 22, 2024

Captcha Image

@nickinformation Tweets

My german Blog: 

http://www.software-virtualisierung.de

in