Thursday, February 28, 2019

Calculations with Adobe Forms radio buttons

 Calculating Adobe Forms


Its been a long while since I've blogged.  I had an interesting small project land on my desk that required calculating values based on radio buttons in an Adobe form.  Initially, I figured this was a simple task that any office worker with intermediate knowledge could do.  After digging into it farther I discovered Javascript had to be used for anything more than a simple sum, product, average, minimum or maximum. 

The thumbnail picture at the beginning of this blog is just a small part of the form I had to work on.  In this blog post, I will create a 5x4 table with radio buttons.  At the bottom, I will sum the choices based on their value. Then I will find the sum of all the columns and find the mean of the choices.

I started out by creating a basic document in Microsoft Word.
Test PDF form image

After creating the PDF, I added the form fields and radio buttons.  The group names were Question1, Question2, etc.  Each button had the Radio Button Choice set to a unique value for each button group. For instance Question 1, and Question 2, both had 4,3,2,1, and 0.

Test PDF From with form buttons and boxes imageTest PDF Form Fields sidebar image


That value was set by either right-clicking the button and selecting Properties or double-clicking the option under the question and entering the value.
Test PDF Form radio button options image
 After the radio buttons were set, I added simple text boxes for each column. Lastly, I added a Sum box and a Mean box.

Now that the form fields exist on the form, it is time to start adding the calculations.

I started with the first column, the 4s column.  I went into the properties of the Total4s text box. I selected the Calculate tab, chose the "Custom calculation script", and clicked Edit.

This is the way I choose to calculate the values. I am certain there are other ways to accomplish this but this method seemed the most straight forward and scalable option for less tech-savvy users.



The first variable total4s is how we will track the number of buttons selected in the 4 column.  I set it to 0 to make sure we are starting from the same place every time.  Next, I use this.getField("Question1").value to get the value of the button selected.  If the radio button in column 4 on Question 1 is selected, the value will be 4 based on the "Radio Button Choice" field referred to earlier.  In my initial testing, I set the value to a variable. I then had the if statement evaluate based on that variable.  After working to simplify the script, I realized I was able to evaluate the getField value directly.

Next, I entered the same code in for each Total3s, Total2s, Total1s, and Total0s.  I modified the variable total4s to match the text box for each column (Total3s = total3s, Total2s = total2s, etc.).  I also changed the condition value in the if statement to match the column number.

After entering the similar javascript in each text box I can test if I receive the expected value.
If the values aren't as expected, you may need to check the Field Calculation Order. The order is top down.  For instance if a calculation depends on a previous calculation, the dependent calculation should be higher in the list.  In this example, the Total*s must calculate before the sum and lastly the mean.


Now I will choose Preview so I can verify I am getting the expected.


At this point, the value only shows a 1 for each selection.  For my needs, I want each selected column to have the value of that column in the total.  So I would like any buttons in the 4 column to return 4 for their total and add up as buttons are selected.  The way I did this was simply by taking the final line of the code event.value = total4s and multiplying it by the column value. Below is what I changed for the last line in each text box.  For the 0 column text box, I don't have any calculations and set the default value to 0.



The next part is adding up the values. Fortunately, we are able to do this with built-in calculations. From the Properties > Calculate tab, I chose "Value is the" and left the default as "sum (+)". When choosing that field, the "Pick" button becomes active.  I chose Total4s, Total3s, Total2s, and Total1s.  Since Total0s will always be 0, I don't need to include it.


Next, I will find the mean.  For that, I'm able to use another option in the Calculate tap under properties for a text box.  "Simplified field notation" is the perfect solution to this.  I just entered TotalSum/4.


After all that, the final product


Wednesday, February 27, 2019

Powershell - Group Policy

A new project came up for me that involved rebuilding our System Center Configuration Manager servers. Being a small environment, our Config Mgr server hosts our WSUS role. Once that server was up and running my next task was to switch over all our clients to the new server. The existing group policy objects weren't best practice and didn't meet our organization requirements. Initially I was planning on reusing the old objects but decided to just scrap them.

The first step was to remove the links using commands similar to this:

 Remove-GPLink -Name "WSUS-OldPolicy" -Target "OU=TargetOU,DC=domain.DC=com"   

I ended up copying this line and changing the Target for each OU I wanted to remove it from.  I also could have read a csv full of the OUs if there was going to be a lot.  I had issues with the Target syntax that I couldn't seem to figure out.  I ended up opening the properties of the OU in ADUC and viewing the distinguishedName.

If I wanted to remove the policy completely I could have run:

 Remove-GPO -Name "WSUS-OldPolicy"  

I typically don't delete policies right away so I'll save that for later.  Running the Remove-GPO cmdlet will also remove the links.

The next step was to create a new policy.

 New-GPO -Name "WSUS-NewPolicy"  

Once the policy is created you can link it to the OU that needs it.

 New-GPLink -name "WSUS-NewPolicy -target "OU=TargetOU,DC=domain,DC=com"  

A shorthand to combine the commands and only need to link it to one place would be:

 New-GPO -Name "WSUS-NewPolicy" | GPLink -target "OU=TargetOU,DC=domain,DC=com"  

Now that the GPO has been created and linked.  You can edit it to the configuration you want.

*Note: I typically don't link GPOs until after they have been configured.  Then I link them to my test OU and test them.  After those steps do I finally link them to production OUs and I typically start with a couple lower priority ones, then link it to all production OUs.

Monday, February 9, 2015

Distributing and Deploying an Application in SCCM 2012 R2 with Powershell

     So it's been a little while since I blogged.  Its been a busy winter and not much happened in my world regarding automation and powershell.

I finally got some time, while waiting for our new surveillance DVRs to arrive, to work on using Powershell with SCCM.  We have our computer labs in their own collections and deploy much of the same software to them.  The main issue we run into is determining how many computers in each lab got the deployed software application.  Yes, I know there are reports that I can run.  The SCCM server I inherited didn't have it installed and I had to get it set up.  I also know that it is working and use the reports quite frequently.  The issue we were having is that we wanted a 5 second look instead of a 5 minute.  The reporting is good, just not quick enough for me or any of my team members.

That's my reason, whether its good or not.  Here we go!

One part of this process I don't have is creating the Application from Powershell.  I still do this manually.  Hopefully, a future post will cover this.

Now I have an Application I have created.  The first step from this point is to distribute the content.  The first thing I did was go to the Technet site for the Start-CMContentDistribution cmdlet.

The command I used was:
 Start-CMContentDistribution -ApplicationName "Adobe Flash Player 16.0.0.305" -DistributionPointName "SCCM.EKHOFF>US" -DistributionPointGroup "HEADQUARTERS"  

I initially had trouble with this command.  I was using -CollectionName along with the Distribution Point parameters.  Turns out I didn't need it. I did have to create a Distribution Point Group and add our single server to it.

After checking the Content Status and verifying it was distributed I was ready to deploy to my collections.  I had forgotten about the distribution step but I received an error when I tried to deploy my first Application.

Again I went to Technet to Start-CMApplicationDeployment

The command I settled on was:

 Start-CMApplicationDeployment -CollectionName "Tech Test" -Name $AppName -AvaliableDate $Date -AvaliableTime $Time -DeployAction Install -DeployPurpose Required -UserNotification DisplaySoftwareCenterOnly -OverrideServiceWindow $true -RebootOutsideServiceWindow $false  

With all the options I wasn't sure where to start.  I ended up going through the deployment manually to see what I actually changed and set.  From there I had a pretty good I idea of what I was looking for.  After successfully deploying to one collection I knew I need this to scale to all labs.

I created a menu to deploy to the most common situations.  Right now we'll look at number 1.

 1. Deploy to All Labs"
 2. Deploy to All Netbooks"
 3. Deploy to Teachers and Staff"
 4. Deploy to Tech Test"

My first thought was to  just have a separate Start-CMApplicationDeployment for each lab.  After looking at the script and the length I decided I needed to make the code cleaner and easier to update.  We have around 40 netbook carts which would have made this code extremely long.

1:  $labArray = @("C107", "C109", "C111", "W208", "W210", "W212", "W216", "W229", "EE154", "EE156", "PCLAB", "StudyHall")  
2:  #All Labs selection  
3:  If($menu -eq 1){  
4:    foreach ($element in $labArray) {  
5:    Start-CMApplicationDeployment -CollectionName $element -Name $AppName -AvaliableDate $Date -AvaliableTime $Time -DeployAction Install -DeployPurpose Required -UserNotification DisplaySoftwareCenterOnly -OverrideServiceWindow $true -RebootOutsideServiceWindow $false  
6:    }  
7:  }  

Thursday, November 13, 2014

Powershell - Disable and Move user

  We have quite a bit of mobility with our students.  When a student leaves we typically hold on to their accounts for a while.  It seems more often than not, we get them back a couple months later.  Typically we just disable them and move them to an Organizational Unit(OU) to keep Active Directory(AD) clean.  Again, as in my last post, this is pretty simple in Active Directory Users and Computers(ADUC).  The issue I run into is I don't always have ADUC open and with Windows 7 and newer it seems to take a little longer than it should to open.  Fortunately, I usually have the Powershell ISE open.

Here's what I do:

 $user = Read-Host "Please enter the user to disable(Logon Name)"  

This lets us enter in the person we want to disable through a prompt.  Once the username is entered, the below command disables the user.

 Disable-ADAccount -Identity $user  

If you know the user's logon name or have the Distinguished Name you could skip the Read-Host and just enter the username in place of the $user variable

The last step is to move the disabled account to a different OU.

 Move-ADObject -Identity $user -TargetPath "OU=ToDelete,OU=Students,DC=test,DC=com"  

This works well and does everything I need.  However, it's 3 lines and I try to keep things as short as possible.  I haven't put in enough time to get it to 1 line, so I'll settle for 2.

 $user = Read-Host "Please enter the user to disable(Logon Name)"  
 Disable-ADAccount -Identity $user | Move-ADObject -TargetPath "OU=ToDelete,OU=Students,DC=test,DC=com"  

Hope this helps someone.

Wednesday, November 12, 2014

Powershell - Unlock AD Accounts

   One of the first issues I have encountered is when the school year starts and all the students come back.  We reset everyone's password just before school starts to help reduce the forgotten password issues.  While this has shown to reduce password issues, with 2000+ kids, some are bound to forget.  In order to make this quick and simple, I turned to powershell.  While Active Directory Users and Computers(ADUC) is quite easy to unlock accounts, I wanted to make it a little quicker.  Here's what I used:

Search-ADAccount -LockedOut

This command searches through all of Active Directory and returns the accounts locked out.  From there I can run:


Unlock-ADAccount -Identity <SAMAccountName> or <Distinguished Name>

The Search-ADAccount commmand returns the SAMAccountName and Distinguished Name which the Unlock cmdlet can handle either one:

Unlock-ADAccount -Identity AndyE

Unlock-ADAccount -Identity "CN=AndyE,OU=Users,DC=domain,DC=com"


While these are nice for handling one account at a time, I run into situations where there is a line of students outside my door with locked out accounts.

I needed a faster way to to unlock accounts than one at a time.  Luckily, with the pipline symbol I can combine more than one command.  This ultimately led to me using:

Search-ADAccount -LockedOut | Unlock-ADAccount

If you maybe haven't noticed, I prefer one liners to get things done.  I have written fairly complex scripts for creating users and other tasks.  I still prefer the quickest and easiest way to accomplish a task.  I'm sure there are probably more elaborate ways to handle these issues, these commands are what works for me and my environment.