Tag Archives | SCCM

Deploy Visual Studio 2010 vai SCCM (silently)

I wanted to have Visual Studio 2010 on my machine. My motto is that if I have to install it, I should package it up in SCCM, so when I re-image, I can just press a button. Here were my steps. Nothing ground breaking in this post, but I wanted to document it for my self (and anyone else that could use it). Also, I am only documenting the steps that I feel are important, so maybe this will be a quick reference for someone.

First I needed to create an answer file: D:\setup\setup.exe /createunattend c:\VS2010_deployment.ini This will walk you through the install and save the settings to an ini file.

Second I added Visual Studio 2010 to SCCM via “new Package from definition” and changed the command line to Setup\setup.exe /UnattendFile \\SCCMServer\smspkgc$\PackageID\Setup\VS2010_deployment.ini

Third I changed the advertisement to “Run program from distribution point”

That was about it. Pretty easy.

Run a task sequence after completed OSD

We wanted to run a Task Sequence after an Operating System Deployment. The OSD image would have only Office,Antivirus, and Windows. The task sequence would have all the other common packages we roll out (Adobe Reader and Flash, Firefox, Quicktime, Java . . .). The problem was that I wanted an easy way to deploy all the packages at once, and an easy way to keep it up to date.

First we created a Collection (that updates every 5 mins) based on the following query:

SELECT SMS_R_System.Name, SMS_G_System_OPERATING_SYSTEM.InstallDate 
FROM SMS_R_System inner join SMS_G_System_OPERATING_SYSTEM on SMS_G_System_OPERATING_SYSTEM.ResourceId = SMS_R_System.ResourceId 
WHERE DATEDIFF(dd,SMS_G_System_OPERATING_SYSTEM.InstallDate,GetDate()) < 2
ORDER BY SMS_G_System_OPERATING_SYSTEM.InstallDate DESC

This query returns all the machines that have had their operating system installed in the last 2 days.

Next we created a Task Sequence that Installed all the packages, and advertised it to the new collection.

Now within a few mins of a machine adding itself to SCCM, it will show up in the collection, and the Task Sequence will be able to be run.

The key was the query to find the machines that have been installed recently. Thanks xrobx99 for your help with this!

A second addition to my PowerShell install script

I added even more functionality in my PowerShell install script (original script, and first update). I wanted the ability to display an informational popup to let the user know what we were up to. The function below takes the text to display from the config xml file and displays it in a windows form, with an “OK” button.

This script is starting to be fun!


Function DisplayWindowsForm ($Step){
	if ($Step.TextToDisplay.Value -ne "") {
    	$TextToDisplay = $Step.TextToDisplay.Value
		[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
		[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
		
		$objForm = New-Object System.Windows.Forms.Form 
		$objForm.Text = "Title bar"
		$objForm.Size = New-Object System.Drawing.Size(600,500) 
		$objForm.StartPosition = "CenterScreen"
		
		$OKButton = New-Object System.Windows.Forms.Button
		$OKButton.Location = New-Object System.Drawing.Size(250,400)
		$OKButton.Size = New-Object System.Drawing.Size(75,23)
		$OKButton.Text = "OK"
		$OKButton.Add_Click({$x=$objTextBox.Text;$objForm.Close()})
		$objForm.Controls.Add($OKButton)
		
		$objLabel = New-Object System.Windows.Forms.Label
		$objLabel.Location = New-Object System.Drawing.Size(10,20) 
		$objLabel.Size = New-Object System.Drawing.Size(500,400) 
		$objLabel.Text = $TextToDisplay
		$objForm.Controls.Add($objLabel) 
		
		$objForm.Topmost = $True
		
		$objForm.Add_Shown({$objForm.Activate()})
		[void] $objForm.ShowDialog()
	}
}

An update to my new PowerShell install script

I needed new functionality in my PowerShell install script (previously mentioned here). I needed the ability to make sure a process is not running, and if it is running, I could prompt the user to close it.

The new function takes the process name value from the config xml file (as I mentioned in previos post) and if it is running, displays a message box until the program is no longer running.


Function WaitForProcessToStop ($Step){
	$ProcessName= ($Step.ProcessName.Value).split(".")[0]
    if ($ProcessName -ne "") {
		[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
		While (get-process $ProcessName -ea SilentlyContinue | select -Property Responding)
		{
			[System.Windows.Forms.MessageBox]::Show(
			"Please close $ProcessName", 
			"Please close $ProcessName", 
			[System.Windows.Forms.MessageBoxButtons]::OK, 
			[System.Windows.Forms.MessageBoxIcon]::Information,
			[System.Windows.Forms.MessageBoxDefaultButton]::Button1,   
			[System.Windows.Forms.MessageBoxOptions]::ServiceNotification
			)
		}
	}
}

SCCM afterbackup.bat

Our current SCCM backup is targeted to DFS share pointed to our backup server. We dump files to this share and the local files are backed up to tape (really to disk then replicated to tape.) I never sat down and figured out how to get multiple backups rotating in SCCM until I saw this post. It reminded me that I needed to setup an afterbackup.bat script. If you add a script named afterbackup.bat to c:\Program Files\Microsoft Configuration Manager\inboxes\smsbkup.box (or where ever you installed it), it will be executed after the backup is finished. I added the following code to afterbackup.bat

setlocal enabledelayedexpansion
set target=\\Network\DFS\BACKUP\SCCM\%date:~0,3%

If not exist %target% goto datamove 
RD %target% /s /q 
  
:datamove 
move "\\Network\DFS\Backup\SCCM\Current" "%target%"

All this does is move the backup folder to a folder named the day of the week. If the destination already exists, then it is deleted first. Resulting in 7 days of backup.

To test, I started the SMS_STIE_BACKUP service, and in the SCCM logs, I see :
SMS Site Backup task is starting.

SMS Site Backup is starting to copy the files from the snapshot.

SMS Site Backup successfully initiated command file “afterbackup.bat”.

Now I see a folder named “Tues” that contains last night’s backup.

Scratch that off the todo list. Finally.

Powershell script to find and run advertisements that are set to run when NoUserLoggedOn

I have been thinking about how to launch a SCCM package/program before logon. If the user logs on before SCCM executes (like right after a reboot), the NoUserLoggedOn requirement will not be met. GPO software deployment handles this by not allowing the user to log in until the software is installed.

What happens if you combine both software deployment via GPO and SCCM?

So my theory is that I could execute a script wrapped in a MSI and deployed via GPO software deployment. This script would then search for advertisements that are set to run “when no one is logged in” and execute them. Below is that script, not sure if the rest of my theory will work, but this is the first piece.

$AdvNoLogOn = (gwmi -Namespace ROOT\CCM\Policy\Machine\ActualConfig -Class CCM_SoftwareDistribution | where {$_.ADV_MandatoryAssignments -eq $true} | where {$_.PRG_PRF_UserLogonRequirement -eq "NoUserLoggedOn"})
$SMSCli = [wmiclass] "\root\ccm:SMS_Client"
foreach ($Adv in $AdvNoLogOn)
{
$PKGID= $Adv.PKG_PackageID
write-host $PKGID
$SCHEDMESS=(gwmi -Namespace ROOT\CCM\Policy\Machine\ActualConfig -Class CCM_Scheduler_ScheduledMessage | where {$_.ActiveMessage -like "*$PKGID*"})
write-host $SCHEDMESS.ScheduledMessageID
$SMSCLI.TriggerSchedule($SCHEDMESS.ScheduledMessageID)
}

Simple vbscript (HTA) to install fonts via SCCM

We have a group of users that need the ability to install fonts (.ttf and .otf). They are not administrators for their machines, so we usually go down there and install the fonts using runas. Since advertised SCCM programs can run as system, I can write a script to copy the fonts into the fonts directory. If I mark the package as allow user to intereact and run as administrator, the script will pop for the user to pick the fonts they want to install. Here is my hta code that runs once a button is clicked:

	Set objShell = CreateObject("Shell.Application")
	Set objFolder = objShell.BrowseForFolder (0, "Install Fonts From (Source):", (0))
	If objFolder Is Nothing Then
		window.close
	Else
		Set objFolderItem = objFolder.Self
		objPath = objFolderItem.Path
	End If

	Set objFso = CreateObject("Scripting.FileSystemObject")
	Set objFolder = objFso.GetFolder(objPath)
	bolGotFonts = False
	For each objFile in objFolder.Files
		If objFolder.Files.Count > 0 Then
		  If lcase(objFso.GetExtensionName(objFile.Path))="ttf" OR lcase(objFso.GetExtensionName(objFile.Path))="otf" then
			bolGotFonts = True
			DataArea.InnerHTML = DataArea.InnerHTML & "<input type=""checkbox"" name=""" & objFile.Path & """>" & objFile.Path & "</input><br/>"
		  End if
		End If
	Next
	if bolGotFonts Then DataArea.InnerHTML = DataArea.InnerHTML & "<br/><input id=runbutton  class=""button"" type=""button"" value=""Install Font"" name=""run_button""

This code will popup a browse dialog and put the filenames found in the select directory into the HTA’s DataArea.innerHTML (DataArea is just a <div>) with a checkbox and button to initiate the copy of the files:

SUB InstallFont
    DIM colChkElem, strDriveName, objChkBox
    SET colChkElem = window.document.getElementsByTagName("input")
    FOR EACH objChkBox IN colChkElem
        IF objChkBox.Type = "checkbox" THEN
            IF objChkBox.checked THEN
                strFileName = objChkBox.name
                Set objShell = CreateObject("Shell.Application")
                Set objFolder = objShell.Namespace(FONTS)
                objFolder.CopyHere strFileName
            END IF
        END IF
    NEXT
    DataArea.InnerHTML = ""
END SUB

Seems to work!

Default MAPI profiles after using Office Customization Tool

We are rolling out a new windows 7 desktop (via sccm task sequence) and one of the packages is the newly released Office 2010. I have been using OCT to modify the outlook profile via a PRF file. We want to take advantage of “cached mode” so that is one of the setting I use the PRF and OCT to set. What if I wanted to change the behavior of one machine, so that it does not use “cached mode”? Do I have to re-install office?

Seems that the default mapi profile is created by importing the PRF file. In windows 7, this registry setting can be found here:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\14.0\User Settings\{GUID}\Create\Software\Microsoft\Office\14.0\Outlook\Setup\ImportPRF

And in Windows 2008 R2 X64 it is here:

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Office\14.0\User Settings\{GUID}\Create\Software\Microsoft\Office\14.0\Outlook\Setup\ImportPRF

Just have this registry key (using 8.3 names) point to a PRF with different settings and the new MAPI profiles will use this PRF.