Using signed PowerShell scripts with configuration items and applications

Edit: The deployment type detection method issue will be resolved in 1706 Current Branch. It will also be available for testing in 1705 Technical Preview.

In the past if you wanted to use a signed PowerShell script as a configuration item detection method or deployment type detection method, you would see an error on the client when it tried to process the script. Configuration Manager 2012 R2 CU2 has a fix in place to mitigate this problem and allow for using signed PowerShell scripts in configuration items and detection methods. You can download CU2 from here: Note that the signer of the script must be pre-trusted or else the script will continue to fail.

For this new functionality to work both the administrator console and client needs to be updated to R2 CU2 as this fix requires changes to both pieces of the product.

First let's talk about configuration item detection methods. To add a signed PowerShell script, when editing a discovery or remediation script you must use "Open" to add the signed script. You cannot copy and paste it. There's a UI change in that the script becomes read only in the admin console until you "Clear" it or change the data type. This is by design. Once the configuration item gets down to the client it should process the signed PowerShell script without any issues.

Things are more complicated with deployment type detection methods. At this time there is no UI code to allow for signed PowerShell scripts but fortunately the client-side fix to allow for signed PowerShell scripts applies both to applications and configuration items. You can use the PowerShell script attached to this blog posting to add a signed PowerShell script to a deployment type in a way the client will be able to properly process. The way it works is you edit the top few lines in the script to match your environment's site code and provider host name. Please also read the information in the header of the script carefully. Notably it will overwrite any previous script in your deployment type. If you edit the script in the admin console after adding it using this script, the script will fail on the client. There's examples in the header of the PowerShell script showing how to use it.

Feel free to let me know if you have any further questions!


Comments (4)

  1. Jared-DOR says:

    I wanted to add my experience here, also posted in the Microsoft Connect forums.  I have been banging my head against my desk for the past week trying to get this sorted out with our CIs.

    We also originally found this problem while running 2012 R2 CU1 on our server, consoles, and clients.  According to the CU2 KB, this issue was fixed.  So we decided to upgrade to CU4 as it was the current version.  We pushed installed CU4 on our server, and updated our consoles and clients.  But we still received an error with our CIs of "script is not signed".  We tried creating new CIs using CU4 and the 'open' method (not copy and paste) to add a PS script as the CI's detection method, but that didn't work either.  However, running the scripts in the client's PS environment worked flawlessly.

    Scaneol's post was correct.  When using the Set-AuthenticodeSignature cmdlet in PS to sign a script it adds one final extra CR at the end of the script.  The CM UI still drops this blank CR line regardless of how it is added (opening the script or copying/pasting) which invalidates the signature.  I further verified this by inspecting the CI's DesiredConfigurationDigest using the cmdlet Get-CMConfigurationItem and looking at the property SDMPackageXML.  Within that XML configuration, the blank CR was missing after the script line "# SIG #End signature block".

    However, I was able to get a workaround in place from that point in PS.  I passed the SDMPackageXML property into an XML type variable so that I could work easily with the XML elements themselves.  I then change the value of the element DesiredConfigurationDigest.Application.ScriptDiscoveryInfo.Script to a string type of the contents of the signed .ps1 script.  Then, I exported this modified XML structure out to a temporary file.  I was then able to use Set-CMConfigurationItem by using the parameter -DesiredConfigurationDigestPath and supplying the temp XML file that included the correct script with the blank CR.

    After I deployed a baseline with the newly revised CI, the clients could then process the signed script without error.

    I would consider my process to be an involved workaround as this would need to be done for every CI.  However, I did not find that this issue was resolved even by CU4.

  2. Jared-DOR says:

    Apologies for my previous comment, it was not correct.  It turned out the CI and baseline I had been testing with was accidentally configured and appeared to be working when it was in fact not.

    However, it did make me dig deeper, and I noticed two things:

    1)  The resultant script that CM generates for the client is encoded in UCS-2 Little Endian.  This is different from what PowerShell's ISE UTF-8 encoded scripts.  Although the textual content between the CM generated script and the original script is precisely the same when compared, the encoding differences appear to cause a different signature when the CM generated script is resigned.  Simply encoding a script in UCS-2 Little Endian and signing it still does not work because:

    2)  Both PowerShell ISE and Set-AuthenticodeSignature cmdlet generate a Character Return (hex value "0D") for each line they create.  The Set-AuthenticodeSignature cmdlet accounts for these CR characters when signing the script.  CM at some point strips off all character returns from any script and simply retains the Line Feeds (hex value "0A").  That causes the signatures to not match, even though the files are precisely identical in textual context.

    It appears that the issue lies with how CM handles script encoding and Character Returns within a script.

  3. Thank you for sharing this. One question: is this script suitable for use with “script” deployment types, instead of “MSI” types? e.g. changing to

    if($deploymentType.Technology -in “MSI”,”Script”)

    1. I dared to try: it seems that the script was loaded correctly, and that now the detection script works fine.

Skip to main content