N-2 WIM and Task Sequence Managment

, ,

After my experience at MMSDE and talking with not only other attendees, but speakers that I knew of and those that were new to me, I felt like I could add something that could help others out there as I have been helped along the way.

Managing multiple WIM files and task sequences can be genuinely time consuming, especially if you have been doing it manually.  That was why I’ve been automating as much as possible over the last year.  Extracting WIM files, making them patch current every month, and then building and capturing WIM files with various versions of Office.  Most of which I have been able to script through trial and error as I got a chance to.

What I wanted to share is my script for updating our Operating Systems and Upgrade packages using the N-2 method.  It is my latest script, but it can help set up your WIM files in the same way and see when I will post the other processes in the near future.   I do not currently have a lab environment to get screenshots yet, but that will also change as I figure out which way to go.

For this script, you can run this on any machine that has the Admin Console installed on it.

These are all examples of how the script is currently set up, to give you an idea for naming conventions for static packages that you can use and customize the script for your own environment.

NEW_1809_WIM

_PROD_1809_WIM

1_PREV_1809_WIM

2_PREV_1809_WIM

For the upgrade packages, it is similar, however they are based on language using EN-US as the example.

NEW_1809_en-us

_PROD_1809_en-us

1_PREV_1809_en-us

2_PREV_1809_en-us

NEW would be your newly updated WIM files and the _PROD your current WIM files.  1_PREV the previous month, and 2_PREV being two versions older.

Here are the steps to acquire your OSD WIM package ID’s:

#=+=+=+=+=+=+=+= OSD WIMS =+=+=+=+=+=+=+=
$NEWWIM = (Get-CMOperatingSystemImage -Name “NEW_*$OSVersion*WIM”)
$NEWWIMID = ($NEWWIM.package.ID)

$PRODWIM = (Get-CMOperatingSystemImage -Name “_PROD_*$OSVersion*WIM”)
$PRODWIMID = ($PRODWIM.package.ID)

$PREV1WIM = (Get-CMOperatingSystemImage -Name “1_PREV_*$OSVersion*WIM”)
$PREV1WIMID = ($PREV1WIM.package.ID)

$PREV2WIM = (Get-CMOperatingSystemImage -Name “2_PREV_*$OSVersion*WIM”)
$PREV2WIMID = ($PREV2WIM.package.ID)

Similarly, the following commands will find your upgrade packages:

#=+=+=+=+=+=+=+= Upgrade Packages =+=+=+=+=+=+=+=
# Using the US-EN version as an example
$NEW_ENUS = (Get-CMOperatingSystemInstaller -Name “NEW_*$OSVersion*en-us”)
$NEW_ENUSID = ($NEW_ENUS.package.ID)

$PROD_ENUS = (Get-CMOperatingSystemInstaller -Name “_PROD_*$OSVersion*en-us”)
$PROD_ENUSID = ($PROD_ENUS.package.ID)

$PREV1_ENUS = (Get-CMOperatingSystemInstaller -Name “1_PREV_*$OSVersion*en-us”)
$PREV1_ENUSID = ($PREV1_ENUS.package.ID)

$PREV2_ENUS = (Get-CMOperatingSystemInstaller -Name “2_PREV_*$OSVersion*en-us”)
$PREV2_ENUSID = ($PREV2_ENUS.package.ID)

Using the values obtained above, we first change the names of the OSD and Upgrade packages.

#=+= OSD =+=
Set-CMOperatingSystemImage -Id $PREV2WIMID -NewName “RETIRED_$OSVersion _WIM” -Description “RETIRED”
Set-CMOPeratingSystemImage -Id $PREV1WIMID -NewName “2_PREV_$OSVersion _WIM” -Description “2-Previous Month”
Set-CMOperatingSystemImage -Id $PRODWIMID -NewName “1_PREV_$OSVersion _WIM” -Description “1-Previous Month”
Set-CMOperatingSystemImage -Id $NEWWIMID -NewName “_PROD_$OSVersion _WIM” -Description “Current Month”

#=+= Upgrade =+=
Set-CMOperatingSystemInstaller -Id $PREV2_ENUSID -NewName “RETIRED_$OSVersion _en-us” -Description “RETIRED”
Set-CMOPeratingSystemInstaller -Id $PREV1_ENUSID -NewName “2_PREV_$OSVersion _en-us” -Description “2-Previous Month”
Set-CMOperatingSystemInstaller -Id $PROD_ENUSID -NewName “1_PREV_$OSVersion _en-us” -Description “1-Previous Month”
Set-CMOperatingSystemInstaller -Id $NEW_ENUSID -NewName “_PROD_$OSVersion _en-us” -Description “Current Month”

This will cycle the WIM packages to make the NEW the _PROD and the others trickle down to where 2_PREV becomes RETIRED.

(Note, one of my other processes that I will post will automatically use the RETIRED package and rename them NEW when building the new WIM files.)

Now, this next step you will have to customize the script for your environment.  This will update your task sequences with the _PROD packages.

#=+=+=+=+=+=+=+= Update Task Sequences =+=+=+=+=+=+=+=
# If managing multiple versions, you can set an if ($OSVersion = XXX) also and have the following steps between {}.
#=+= OSD =+=
$PRODWIM = (Get-CMOperatingSystemImage -Name “_PROD_*$OSVersion*WIM”)

Set-CMTSStepApplyOperatingSystem -TaskSequenceId XXXXXXXX -ImagePackage $PRODWIM -ImagePackageIndex 1 #Change XXXXXXXX to your task sequence ID.

#=+= Upgrade =+=
$PROD_ENUS = (Get-CMOperatingSystemInstaller -Name “_PROD_*$OSVersion*en-us”)

Set-CMTSStepUpgradeOperatingSystem -TaskSequenceId XXXXXXXX -UpgradePackage $PROD_ENUS #Change XXXXXXXX to your task sequence ID.

And that’s it.

I have uploaded the script to GitHub so you can grab it instead of copying and pasting from above.

https://github.com/shotgn22/osd

Thank you for reading this far.

My name is Scott Graves, I have been doing IT since 1995 and am currently heavy into OSD, Task Sequences and Upgrades.  I have set up a Twitter (@shotgn22) if you have any questions.  Thank you Adam Gross of ASquareDozen.com and Chris Buck of this page for taking the time to answer my questions the past few days.

Quick and Dirty SCCM Application Deployment Reporting

, , , ,

For this blog, I’m going to go over a very basic script I wrote to quickly get application deployment statuses without having to use the Configuration Manager GUI console. I find the ReportingDeployments tab very slow to respond, and you still have to dig into each individual app if you want details.  What this function does is allow you to specify what you think is the name of the application and it will find anything like it, allow you to select the one you want, and then it will run a deployment summarization and output the results. 

Examples:

Function called with the correct name of the package

In this example, “Tanium Client” is the actual name of a software package, so it doesn’t need to pop up a prompt asking us which one we actually wanted.

Function called with a keyword instead of the full package name
After package was selected from the pop up
In the above two images, I didn’t remember the full name of my Tripwire deployments, so I just typed “Tripwire” and let it look for it for me.  
The Code:

This is a fairly simple piece of code, but I wrote it to run quickly.  It first checks to see if the name you gave it when running already matches a software package. If not, it runs a WMI query (much faster than using Get-CMApplication with a where-object piped on) to look for anything like what you entered. It puts all results into an array which then selects the LocalizedDisplayName and filters out duplicates. Those unique values are then handed over to Out-GridView, which thanks to the -passthru flag assigns the selected result to our original $SoftwareName variable.  You’ll also see that I have to specify that I want the “.localizeddisplayname” NoteProperty. If you don’t do this, you’ll see the selected software name as “@LocalizedDisplayName={‘Whatever your name was’}”
After that selection process, everything proceeds as normal. It gets the CMDeployment object for that application and runs the Invoke-CMDeploymentSummarization cmdlet which refreshes the deployment status, gets you current numbers, etc.  After that, I have it get the deployment again and select what I found to be the relevant values for a list formatted report.  Because SummarizationTime is done in UTC, I have it convert to client local time for ease of reporting, and I also go ahead and do a quick math expression for the percent success, which is done with the Round function so we don’t get a dozen decimal places of needless precision.   The Query Time value was mostly tacked on at the end so the people I was getting this information for could see that the data was current.  
Hopefully this is useful for someone out there. Thanks for reading! 

Distribution Point Migration Tool-Kit

, , , , , , , , , , ,
The toolkit can be downloaded from my Technet Gallery HERE
This post is a long time in coming, but creating something robust enough to work in most environments that’s still user friendly (with associated documentation) can take a little bit of time.  In the course of one contract I’ve worked, we realized that we needed a way to convert old Secondary SCCM sites into Distribution Points, but we wouldn’t be given any new servers to migrate to. We also knew that the WAN links connecting these remote sites back to our headquarters were severely lacking.  Our solution was to prestage all the content currently stored on the content libraries so we could strip off all the roles (which would clear the SCCM content library), remove unneeded programs and features, add the servers back as Distribution Points, and then reload the prestaged content so it wouldn’t have to transfer over our unspeakably slow WAN connection. We got a peek at this work with my last post of the SCCM Universal Prestage script, but this post will give you the other pieces of the puzzle.  

The Core Functions

Initialize-Toolkit
                This is the first function you call if you’re running the Migration Kit from a PowerShell window you didn’t summon up from inside the Configuration Manager console.  This function will verify that you have Administrator rights, will seek out and import the Configuration Manager module, and will map your CMSite PSDrive if you don’t already have it mapped. This function is also called within every other function after a quick check to make sure that the CMSite drive is mapped.  If it isn’t mapped, it calls the Initialize-Toolkit function and maps it. 
 Console run without admin rights
Console run without admin rights
After the drive has been created
Get-DPContent
                The second function in the toolkit will query our primary site server and return a list of all content that is assigned to the distribution point we provided.  There are multiple ways to get this information. I’ve seen it done with Get-CMDeploymentPackage cmdlet since that will also return package type information that we’ll need later.   However, I chose to do it via the SMS_DPContentInfo WMI class because I find that it returns the same level of information, but does so in roughly 1/3 the time.  It also means that you can run the command without needing to be connected to the CMSite drive if you don’t want to fully initialize everything. 
 A simple report of package ID’s and names
An example of the data stored by SMS_DPContentInfo
Prestage-Content
                This is one of the ‘heavy lifters’ of the toolkit.  This function requires a package ID number, the Distribution Point containing the package, and the folder you want it dumped to after creation. What this creates is a PKGX file named with the package ID of whatever you prestaged.  The way it decides what to prestage is based on the PackageType value that comes from WMI’s SMS_PackageBaseClass. Again, you can get a package type identifier from Get-CMDeploymentPackage if you’d rather go that way, but I like WMI.  Once it’s pulled the PackageType value, it runs it through a SWITCH command and runs the appropriate Publish-CMPrestageContent command.  I don’t do any special logging with this function since Publish-CMPrestageContent already does a good job of it.
 Prestaging a single file
Prestaging multiple packages with a For Loop
Restage-Content
                This function is one of the main reasons I like to save my prestage files with the PackageID as the name.  You input the folder containing the prestage files as well as the name of the Distribution Point they need to be assigned to, and this will get the package type information for that package, run the same switch as Prestage-Content, and issue the Start-CMContentDistribution command with the appropriate flags.  Just to save time, it will also query the Get-DPContent function to make sure that it isn’t trying to reassign packages that are already assigned.
Packages were already assigned in SCCM
 Package distribution in progress
Extract-Content
                This function calls upon Microsoft’s ExtractContent.exe tool to run, and is designed to be run locally from whatever DP you’re importing the package to.  The only flag you need to specify is the location of the prestaged content folder.  It takes the hostname of the computer it’s running from and makes a WMI query to see any packages assigned to it that aren’t in State 0.  If the package shows as state 0, then there’s no further work to be done, and we can just work on the others.  There are multiple ways you can run the extractcontent.exe tool, but I’ve found some to work better than others.   Whether you run it specifying a single package to extract or you run it with an entire folder targeted, I’ve found that when I check the Distribution Point Configuration Status in the SCCM console, there’s always some that still show “waiting for prestage content.”  In almost every case where that’s happened, just re-prestaging the content cleared it up. I don’t know if this is a limitation of the extractcontent.exe tool, my impatience, or what, but it works for me.  Because of that, I actually have my Extract-Content function run through the Prestage content folder one item at a time, so you can re-run the function, it will re-query for unsuccessful packages, and only attempt to extract the packages that didn’t make it the first time.
 
ExtractContent running

Example

Stage-LocalDPContent
                I put this together for our SCCM architect who wanted something that he could quickly and easily run while logged into our Secondary Site Server that was being migrated.  What this does is query the local DP for all assigned content, export it with the Prestage-Content function, and give you a progress bar to show you how far along you are.