PS App Deployment Toolkit: User Logged On / Off Deployment Types

I started using PSADT a year or two ago for my commonly updated applications. Flash, Java, Reader, etc.

One of the first issues I encountered was having a single deployment type. Per PSADT documentation, your deployment type should be deployed with “Allow users to view and interact with the program installation” ticked. Unfortunately, if you set “Logon Requirement” to “Whether or not a user is logged on”, this field greys out, unticked.

So, with this box unticked, PSADT proceeded in Noninteractive mode. Instantly closing Internet Explorer and whatever other apps I had specified. This didn’t make me (or anyone else) happy.

My workaround is quite simple. I have two identical deployment types with different User Experiences. Additionally, I have created a Global Condition to determine whether the workstation is currently in use or not (whether locally or via RDP). This Global Condition is set as a requirement on each Deployment Type.

You can create the Global Condition under Software Library -> Global Conditions. I named mine “Workstation in Use”. The discovery script is incredibly simple:

[code language=”powershell”][bool](query user)[/code]

On your “User Logged On” deployment type, configure as such:
User Experience Tab
Installation Behavior: Install For System
Logon Requirement: Only when a user is logged on
Installation Program visibility: Normal
Tick the Allow users to view and interact box.
Requirements Tab
Add -> Custom -> Condition -> Workstation In Use -> Value -> Equals -> True

On your “User Logged Off” deployment type, configure as such:
User Experience Tab
Installation Behavior: Install For System
Logon Requirement: Only when no user is logged on
Installation Program visibility: Normal
The “Allow Users to View and Interact” will be greyed out automatically.
Requirements Tab
Add -> Custom -> Condition -> Workstation In Use -> Value -> Equals -> False

This setup will allow you to give your users the PSADT experience, but also leverage PSADT (in noninteractive mode) to perform installations while no users are logged into the system(s).

 

 

 

Scripting bulk client actions.

I had about 11 applications rolling out this weekend. Tonight, I saw about 200 systems hung up in the “Content Downloaded” status. They were well past the deadline date/time but had not yet enforced. I couldn’t find a common denominator, if I connected to any of them in Client Center and ran the App Deployment Cycle, they installed immediately. My maintenance window was closing, so I needed to focus on resolution rather than going CSI: on the issue.

Current Branch allows you to right click a collection and Notify clients to evaluate Application Policies, but there is not yet the same functionality in the Monitoring tab for particular groups with same reported status on a deployment.

Double Clicking the “Content downloaded” header gives you a copy-pastable list of clients. I stripped out the client names and saved them in a text file. I mass-triggered the Application Deployment Cycle with the following script:

[code language=”powershell”]
$clients = Get-Content C:\users\chris\desktop\clients.txt
ForEach ($client in $clients)
{
Invoke-WMIMethod -ComputerName $client -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule “{00000000-0000-0000-0000-000000000121}”
}[/code]

I suppose you could take the same list and create a collection, then trigger the client notification from the console. I use this simple script frequently for quickly getting things run on clients. Things like cycling the ccmexec service (or changing cache value and cycling ccmexec), where SCCM would not be practical.

SystemCenterDudes has an extensive list of triggers you can plug into this script HERE. You could also use this with the CCMCache script I posted HERE earlier this month.

Deploying ccmcache location and size changes, part two.

If you didn’t read part one, you can find it at this link.

My original issue was with systems during migration defaulting back to incorrect ccmcache location and size values. Rather than continuing to deploy to specific systems to resolve, I went ahead and created a configuration item to ensure all client systems are set to intended values.

If you’re only looking to change the ccmcache size, there is an item for this now in Client Settings policies. Unfortunately, that doesn’t allow for changing location. I haven’t vetted this in a lab, but I wouldn’t be surprised making this change in client settings also locks you from modifying the values client-side. This won’t work for me, I have a small number of applications that break the 5120MB barrier. Not enough that I want to increase all systems cache sizes, but enough that I don’t want to revert to manual installations.

Using a compliance item will allow for me to make changes in the future as needed during installations, but also ensure that the value is changed back to standard afterward.

First, we create a Configuration Item with both a discovery script and a remediation script.

ci-1

When you click Next, you’ll be prompted for a list of applicable operating systems. I selected all as in my environment, I’d like all my configmgr clients using the same values and thus enforced in the same manner. In an environment where separate values may be needed based on demand, you’d likely create multiple configuration items to include in multiple configuration baselines.

ci5

For discovery of the value we’re looking for, we use the following Powershell bit to query the SoftMgmtAgent WMI namespace for the CacheConfig class values. We simply return the values of the cache size and location to console.

[code language=”powershell”]$Cache = Get-WmiObject -Namespace ‘ROOT\CCM\SoftMgmtAgent’ -Class CacheConfig
write-host $Cache.Size $Cache.Location[/code]

ci3

The value returned, in my environment (and by default), should be: “5120 C:\Windows\ccmcache”. We know that if a client system returns anything else, it does not conform to our desired values for ccmcache and we need to run another script to fix that. In the rule creation below, I’m setting the expected returned value from the discovery script and enabling remediation where necessary.

ci6

Our remediation script is pretty simple, too. We know the client’s settings aren’t 5120MB and C:\Windows\ccmcache, so I correct that with the following:

[code language=”powershell”]$Cache = Get-WmiObject -Namespace ‘ROOT\CCM\SoftMgtAgent’ -Class CacheConfig
$Cache.Location = ‘C:\Windows\ccmcache’
$Cache.Size = ‘5120’
$Cache.Put()
Restart-Service -Name CcmExec[/code]
ci4

ci7

The CcmExec service restart is necessary to apply the new values. I was not able to find a documented alternative to this.. so systems that run the remediation script will have their CcmExec service restarted. Implications from this: Software Center instances will close automatically. Potential policy evaluations and subsequent balloon notifications upon service initialization.

I opted to only remediate during maintenance windows for my Configuration Baselines, so this is less of a concern but still something to be aware of.

Once you’ve created your CI, add it to a pilot Configuration Baseline deployed to a small batch of test systems. I generally use a few different Win7, Win10, and usually even an XP system. In this case, I left a few default and changed the ccmcache size and/or location on the bulk of them. Their values were all uniform during the next maintenance window.

 

 

Deploying ccmcache location and size changes

I was working on some deployments today and discovered a large chunk of systems that have had ccmcache location set to c:\ccm\cache and size set to 250MB since I migrated to a Current Branch hierarchy.

I did not want to deploy something to all systems in the target collection for this deployment as the ccmexec service would have to cycle, and I’m not sure what would happen if an install were in progress when that happens. My other option would have been to create a collection with only the machines failing with the same “not enough temporary space is reserved” message, and deploy a fix app/package to it.

In the end, I had the list of clients with “not enough space reserved” and just ran the following from my system:

[code language=”powershell”]Invoke-Command -ComputerName PCNAMEHERE,ANOTHERPC,ANDANOTHER,YETANOTHER -ScriptBlock { $Cache = Get-WmiObject -Namespace ‘ROOT\CCM\SoftMgmtAgent’ -Class CacheConfig
$Cache.Location = ‘C:\Windows\ccmcache’
$Cache.Size = ‘5120’
$Cache.Put()
Restart-Service -Name CcmExec }
[/code]

In the future, I’ll probably look at spending some time creating a configuration item with this script utilized for remediation.

Creating a ConfigMgr lab environment

I’ve been toying with the idea of bringing up a lab for tinkering around with Configuration Manager lately. It’s something I’d love to do at work but there’s not enough time and never will be. Since Windows 10 offers the Hyper-V role, I decided to give it a shot. I’m running all of this on a Core i5 w/ 16GB RAM until I can build up something more substantial.

My background is desktop support. I spent a few years at Geek Squad driving the bug, setting up wireless routers, and watching the company slowly turn technicians into sales people. This drove me to corporate I.T. and desktop support. I spent three or four years doing that before I had finally picked up enough responsibilities to make it official as a system admin. That said, I’ve never had the opportunity to setup a domain from scratch before, outside of the labs for the MCSA course for Server 2012. A few downloads and a couple VMs later..

sccmchrisdomainjoin

I’m not going to make step-by-step instructions for getting the labs ready for ConfigMgr as there is plenty out there. Here are some useful links and my notes. My daily work is in an environment with a CAS and three primaries with 8 DPs. For now, my lab will consist of a standalone Primary site with all roles.

It’s worth noting that in production, I’ve read that you shouldn’t use an external DNS name for your AD forest. Not a problem in this lab environment, but in the real world I’d do something like corporate.sccmchris.com. Not sure of all the ramifications, but if I gave them Internet access I know my clients wouldn’t load this blog by visiting “sccmchris.com” without being preceded by www. It also goes without saying that this is a bare minimum configuration to bring up a working domain, and I won’t be focusing on Best Practices other than Configuration Manager stuff.

Domain Controller: DC.SCCMCHRIS.COM
Primary Site Server: CM-PRIMARY.SCCMCHRIS.COM
Windows 7 Ent. Client: CLIENT-W7.SCCMCHRIS.COM
Windows 10 Ent. Client: CLIENT-W10.SCCMCHRIS.COM

Downloads and notes..

Windows Server 2016
https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2016

Configuration Manager 1606 / CB
https://www.microsoft.com/en-us/evalcenter/evaluate-system-center-configuration-manager-and-endpoint-protection

SQL Server 2016
https://www.microsoft.com/en-us/evalcenter/evaluate-sql-server-2016

Sweet packaged Hyper-V systems for Windows 7, 8, 10.
https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/#downloads

Lab Setup Guide
https://docs.microsoft.com/en-us/sccm/core/get-started/set-up-your-lab

Install Server 2016 on DC VM
Install Server 2016 on Primary VM
Create External switch in Hyper-V for DC Internet access (optional)
Create Internal switch in Hyper-V for use between VMs
On DC, install DNS/DHCP/AD DS roles.
Promote system to DC, create forest
Add second network adapter on internal network virtual switch, configure static IP. I used 10.0.0.1. This adapter will be on the same virtual switch as all other VMs.
Configure dhcp. add a scope to assign 10.0.0.2-.254/24, set router and all else to 10.0.0.1
Connect other systems virtual adapter to the internal network
clients receiving IPs after this step.
Create a domain user, add to domain admins
Join clients to newly created domain with new account

Creating snapshots and calling it a day. Ready  to begin pre-req installation for 1606!

Collecting local group membership/local admin details via Compliance Settings in ConfigMgr

Hi all! I wrote this some time ago back before my environment rebuild and content migration. As a result, some of this is not necessary (for instance, Report Builder worked out of the box on Server 12 R2 for me), but thought this was worth sharing with you guys.

I was asked to create a report to show what accounts and groups were inside of the Administrators group on all of our client systems. I found a post by Sherry Kissinger back with SCCM’07 I believe, which lead me to the post below, updated with logging for SCCM2012.. Shout out to Sherry for this post, please reference it for the MOF for extending hardware inventory and further information: https://mnscug.org/blogs/sherry-kissinger/244-all-members-of-all-local-groups-configmgr-2012 .

This was written for a CAS running Configuration Manager 2012 SP1 on a Windows Server 2008 R2 host.

Preparing the console host for report builder 3.0

Please note that I only had to do this when running SQL ’08 on Server ’08 R2. Leaving instructions here for reference.  Worked fine with Server ’12 R2 and SQL ’16 out of the box. The first thing we want to do is get SQL Server 2008 R2 Report Builder 3.0 working. By default, you’re going to get a message saying whatever MP you’re connected to is missing the click-to-run application. You will want to do this on your MP, indeed, as we’ll use it to build our report later. Contrary to the message, you need to do this on any client running the console that you intend to edit reports from in the future as well.

  • Install .NET Framework 3.5.1
  • Install Report Builder 3.0
  • Open Notepad as an administrator and open the console config
    • Path: C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\Microsoft.ConfigurationManagement.exe.config
  • Under “ReportBuilderMapping”, change the last two (of four) lines from 2_0_0_0 to 3_0_0_0 and save.
  • Launch the SCCM console and go to Monitoring -> Reporting -> Reports, then verify that clicking “Create Report” successfully launches Report Builder 3.0

Creating the configuration item

lgm_1

We need to create a custom WMI namespace to hold the information we’re looking to obtain. We do this by creating a configuration item.

  • Assets and Compliance -> Compliance Settings -> Configuration Items -> Create Configuration Item

lgm_7

lgm_3
This script was written by Sherry Kissinger and can be found via the link to her blog I mentioned earlier.

I’m not currently enforcing any compliance rules with this since I am looking to monitor, not remediate with this setting. This should work as long as WMI isn’t broken, in which case, you’ll have bigger issues with the client than just compliance settings.

lgm_6

Creating the configuration baseline

Local Group Membership is the only configuration item/baseline in use in my environment right now. This can contain all of your configuration items in the future, I have created one for top-level items (company-wide) and one for each site with their own SCCM admin as I use RBAC and allow the site admins to do their own thing with daily operations in general. This allows me to scope this out to keep it out of the hands of less-experienced admins. Note that you can include other configuration baselines in a configuration baseline, so you can create additional baselines for settings/configuration items that only apply to subsets of your All ConfigMgr Clients collection.

  • Assets and Compliance -> Compliance Settings -> Configuration Baselines -> Create Configuration Baseline
  • Add your configuration item and any other desired items (software updates, other configuration baselines, config items)
  • Deploy the newly created configuration baseline to your desired collection. I originally set our schedule to be simple, run every 1 days. I found that there was a dire need for this data to be current when Software Inventory ran (we schedule for once daily, but that time can vary with randomization and laptops), so have since changed to every 6 hours. When deployed, it’s my understanding that the clients will run it immediately, then your schedule will take effect.

Configuring the Hardware Inventory Classes

We now need to populate the new namespace with data. This data is gathered by the configuration item and submitted to the management point during Hardware Inventory. Please reference Sherry’s post for the MOF, you’ll use it to add the cm_LocalGroupMembers class. Afterward, you’ll just need to make sure the class is enabled in your client settings policy.

  • Administration -> Client Settings -> Client Settings – ABC -> Hardware Inventory -> Set Classes -> LocalGroupMembers (cm_LocalGroupMembers)

Building the report

We’re collecting the data now, we just need to create the report to view it. You can also create a subscription to this report. Note: I did this on the MP directly (or wherever your SQL is hosted)… if you create the report from a client, from my understanding you’ll have to import the sql server certificate and such… easier to just create on the MP.

lgm_9

  • Monitoring -> Reporting -> Reports -> Create Report
  • The report is created and opens in Report Builder 3.0
  • Right click Datasets, Add Dataset. On the Query tab, click “Use a dataset embedded in my report.”
  • Select the AutoGen datasource
  • Enter the following as a text query

[code language=”powershell”]select sys1.netbios_name0
,lgm.name0 [Name of the local Group]
,lgm.account0 as [Account Contained within the Group]
, lgm.category0 [Account Type]
, lgm.domain0 [Domain for Account]
, lgm.type0 [Type of Account]
from
v_gs_localgroupmembers0 lgm
join v_r_system_valid sys1 on sys1.resourceid=lgm.resourceid
where lgm.name0 = ‘Administrators’
order by sys1.netbios_name0, lgm.name0, lgm.account0
[/code]

  • Click “refresh fields”. You’ll be prompted for credentials, I used my reporting services account
  • The “Fields” tab will populate with the localgroupmembers0 fields. OK out of this dialog.

Let’s setup the report to display the data now.

lgm_2

  • Click “Table or Matrix”, then Dataset1, then Next
  • Drag all available fields to Values
  • (next, next, finish). Save your newly created report.

I created this report on my CAS to report across my 3 primaries.

lgm_4

You may have to play with the report to get the display to your liking, but the above steps gave me the following results from the console.

lgm_8

That’s it. I recently built a new hierarchy from the ground up and performed a content migration, which meant extending hardware inventory again and recreating all my custom reports. Still working with ConfigMgr CB v1607, Server ’12R2, and SQL 2016.

lgm_5

 

Securing Java Runtime without crippling clients.

One of the issues I’ve run into with patching Java Runtime is that for the last few years,  unsigned / self-signed applets are blocked by default. You can whitelist websites on a per-system basis, but I ran into the need to deploy this to a number of systems. This seems way more complex than it has to be. Here’s how I build the Java Enterprise Deployment Ruleset.

The easy parts….
1. Get a code signing certificate from an authority trusted by your client systems. You need to be able to export it with private key.
2. Install JDK
3. Export cert as PFX, save into programfiles\jdk\bin
4. Rename .PFX to .p12
5. Create ruleset.xml per http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/deployment_rules.html

The difficult stuff.. now it will probably be easier for you than it was for me.
1. Create a JAR with the ruleset.xml:

[code language=”powershell”]jar -cvf DeploymentRuleSet.jar ruleset.xml[/code]

2. Import your .p12 certificate into a Java keystore.

[code language=”powershell”]keytool -importkeystore -srckeystore whatever.p12 -srcstoretype pkcs12 -destkeystore signing.jks -deststoretype JKS[/code]

You will be prompted to create a keystore password, also prompted for the password you specified when you exported your cert.

3. Find the private key for your cert in the keystore (hint: it’s before the date in the 1 entry listed)

[code language=”powershell”]keytool -list -keystore signing.jks[/code]

You will be prompted for the keystore password as well as the password you specified when you exported your cert.

4. Sign the JAR you created.

[code language=”powershell”]jarsigner -verbose -keystore signing.jks -signedjar DeploymentRuleSet.jar DeploymentRuleSet.jar long-key-name-here[/code]

You will be prompted for the keystore password as well as the password you specified when you exported your cert.

The wrap-up…
1. Verify the JAR is signed OK

[code language=”powershell”]jarsigner -verify DeploymentRuleSet.jar[/code]

2. Test the DeploymentRuleSet locally
Copy DeploymentRuleSet.jar to C:\Windows\sun\java\deployment.
Check the “Configure Java” app, the Security Tab should display “view the Active  Deployment Rule Set”.
The resulting window should include the file’s contents as well as “DeploymentRuleSet.jar is valid”

3. Deploy the JAR to clients
The signed JAR should be placed in C:\Windows\sun\java\deployment on clients. I use GPO to achieve this. You could also create a PowerShell script to copy the file and an application in ConfigMgr with a detection method based on file and modified date. This would allow you to update the source content’s JAR, then update content on the deployment type, then update detection method… which would force clients to reevaluate the app.

Sample of what’s in ruleset.xml:
[code language=”xml”]
<rule>
<id location="http://whatever/Whatever"/>
<action permission="run"/>
</rule>

<rule>
<id/>
<action permission="default">
<message>
This application requires additional configuration to run.
Please submit an email to Help Desk.
</message>
</action>
</rule>
[/code]