Archive | 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.

My offline Exchange 2010 install script

As I mentioned in my previos two posts, I am creating an offline replica of our Windows environment in order to test migrating from Exchange 2003 to Exchange 2010.  Now that I had a replica of our Exchange 2003 server running, I wanted to add a new Exchange 2010 box. I already had a SCCM OSD with 2008 R2 that installs the box and adds it to the domain (in this case it is the fully functioning offline domain). I added the new SP1 to meet all the prerequisites. Then I used the following commands:

#In powershell (I had to do it twice for some reason)
Import-Module ServerManager
Add-WindowsFeature NET-Framework,RSAT-ADDS,Web-Server,Web-Basic-Auth,Web-Windows-Auth,Web-Metabase,Web-Net-Ext,Web-Lgcy-Mgmt-Console,WAS-Process-Model,RSAT-Web-Server,Web-ISAPI-Ext,Web-Digest-Auth,Web-Dyn-Compression,NET-HTTP-Activation,RPC-Over-HTTP-Proxy -Restart

Set-service NetTcpPortSharing -startuptype automatic

.\setup.com /PrepareAD
.\setup.com /mode:install /roles:mb,ht,ca

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)
}

My CEWP JQuery code to play flash files in a Modal

I have Flash files in a Document Library. I wanted to have users click the flash files (swf) and have them open up in a hidden div, rather than opening in a different window. I added the code below to a CEWP:

<script type="text/javascript" src="http://jquery.thewikies.com/swfobject/jquery.swfobject.1-1-1.min.js"></script>
<script>
$(document).ready(function() {
//
$("#popupclose").click(function () {
	$("#popup").Hide();
	$('.media').flash().remove();
	return false;
});
//
$("a[href*='\.swf']").each(function(){
	this.onclick = function(){
	var filetoopen = $(this).attr("href");
	$("#popup").Show;
	$('.media').flash({swf:filetoopen,height:600,width:1000});
	return false;
	};
}); 
//
});
</script>
<style type="text/css">
#popup{  
 display:none;    
 position:absolute;  
 top: 10px; 
 left: 10px;
 background:#FFFFFF;  
 border:2px solid #cecece;  
 z-index:2;  
 font-size:12px;
 }   
</style>
<div id="popup">  
  <a id="popupclose" href="javascript:void()">close</a>
<br/>
  <div class="media" style="vertical-align:top;"></div>
</div>