Sample #PowerShell code for my TechEd Session – Demo 1 – Create and Deploy an Application

Here’s example code for my first demo at our TechEd session. Review the session here PCIT-B410. The code below is an extended version of what I showed in the session (or at least attempted to show, the demo gods were against me …),

Download the script…

Here’s a brief overview of the script:

  • Import ConfigMgr module
  • Create a new application
  • Create a new deployment type for the (modern) application
  • Create a new schedule for the collection (update collection membership daily)
  • Create a new user-based collection with a query membership rule, and apply the schedule.
  • Distribute the application to “Corporate DPs” DP group
  • Create a new simulation for the application
  • Remove the simulation, and create a required deployment

There’s obviously a lot going on in this script, and was meant to show the ability to do an end-to-end scenario. (This becomes significantly harder when you have other deployment types like script-based installer, for example).

Please add your comments for where you would like deeper-dive posts explaining certain tasks.

Download the script…

Happy Scripting!

#Demo 1 - Create and deploy software
#region Import ConfigMgr Module
$CMModulePath = `
    $Env:SMS_ADMIN_UI_PATH.ToString().SubString(0,$Env:SMS_ADMIN_UI_PATH.Length - 5) `
    + "\ConfigurationManager.psd1"
Import-Module $CMModulePath -force
cd PR1:
#endregion

#Show ConfigMgr cmdlets- filter in gridview for Application and Deploymenttype
Get-Command -Module ConfigurationManager | out-gridview
#show help for New-CMApplication
Get-Help New-CMApplication

#region Create New CM Application
New-CMApplication -Name "TestApp Mobile Edge" -Owner "Greg Ramsey" `
    -ReleaseDate (get-date).ToShortDateString() -Keyword "Sales" `
    -IsFeatured $True -SoftwareVersion "1.0.70.75" `
    -IconLocationFile "\\ws2012r2\source$\MobileEdge\testapp.ico"

#Could display the application by running the following:
#Get-CMApplication -Name "TestApp Mobile Edge"

#Show help for Add-CMDeploymentType
get-help Add-CMDeploymentType -ShowWindow

#Add-CMDeploymentType is painful - edit with Show-Command
Show-Command Add-CMDeploymentType

Add-CMDeploymentType -ApplicationName "TestApp Mobile Edge" `
    -AutoIdentifyFromInstallationFile -ForceForUnknownPublisher $True `
    -InstallationFileLocation \\ws2012r2\source$\MobileEdge\testappMobileEdge.Win8App_1.0.70.75_AnyCPU_Debug.appx `
    -Windows8AppInstaller `
    -AdministratorComment "Mobile Edge - Internal App" `
    -AllowClientsToUseFallbackSourceLocationForContent $True `
    -DeploymentTypeName "Mobile Edge for Windows 8" -OnSlowNetworkMode Download `
    -TriggerVPN $True
#endregion

#region Create and populate new CM Collection
#Create schedule *daily*
$sched = New-CMSchedule -start (get-date) -DurationInterval 0 -RecurInterval Days -RecurCount 1 -DurationCount 1
#Create Collection with daily update (no incremental)
New-CMUserCollection -Name "Test Users" -LimitingCollectionName "All Users" -RefreshType Periodic `
    -RefreshSchedule $sched

#Create a WQL Query rule for the collection
Add-CMUserCollectionQueryMembershipRule -CollectionName "Test Users" `
    -QueryExpression "select *  from  SMS_R_User where SMS_R_User.UserName = 'ramseygr'" `
    -RuleName "TestUsers"

#endregion

#region Deploy Software
#send content to DP
Start-CMContentDistribution -Applicationname "TestApp Mobile Edge" `
    -DistributionPointGroupName "Corporate DPs"

#Create a simulation deployment
Start-CMApplicationDeploymentSimulation -CollectionName "Test Users" `
    -Name "TestApp Mobile Edge" -DeployAction Install

#....3 days later... once you have results from simulation
#capture the info in the simulation
$Simulation = Get-CMDeployment -CollectionName "Test Users" | `
    Where-Object {$_.SoftwareName -eq "TestApp Mobile Edge" -and $_.DeploymentIntent -eq 3}

#remove the simulation (because you can't have the same app targeting the same collection)
Remove-CMDeployment -ApplicationName $Simulation.SoftwareName -CollectionName $Simulation.CollectionName -force

#create the deployment, based on information fromt he simulation
#This will create a deployment with a deadline 3 days from today at 8PM local time
Start-CMApplicationDeployment -CollectionName $Simulation.CollectionName -Name $Simulation.SoftwareName `
    -DeployAction Install -DeployPurpose Required -DeadlineDate (get-date).adddays(3).ToShortDateString() `
    -DeadlineTime "20:00" -TimeBaseOn LocalTime

#endregion

How To: Promote an Application Simulation to a Required Deployment in ConfigMgr 2012 SP1

A simulated deployment is a great way to validate detection rules and deployment types prior to deploying an application. In my opinion, there’s one small task that’s missing – the ability to promote a simulation to production.

This post will demonstrate how to create a right-click action on the Monitoring->Deployments tab to promote a simulation to a required deployment.

promotesimulation

Selecting the action “Promote Simulation to Production” will launch PowerShell and display the simulation information (numbertargeted, numbersuccess, numbererrors, etc):

promotesimulation-2

You can also see that by default, the script is configured to create a deadline for 8:00 PM of the date in which the script is run. Be sure to modify the script to fit your needs (as well as avoid surprises).

You can download the .zip file and follow the directions in the included ‘info.txt’ file for a fast deployment to your admin console. You can view additional details below.

First you must create the proper r-click context menu. Copy the following .xml, save it as “PromoteSIMToProd.xml”, and copy it to C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\XmlStorage\Extensions\Actions\d1621955-48ad-4bba-9c85-95f74c0c6538\PromoteSIMtoProd.xml. (Adjust the path as appropriate to your ConfigMgr Admin Console installation path).

<ActionDescription DisplayName="Promote Simulation to Production" MnemonicDisplayName="Promote Simulation to Production" Description = "Removes Simulation and Creates Mandatory Deployment based on Simulation Config" RibbonDisplayType="TextAndSmallImage">
<ShowOn>
<string>ContextMenu</string>
<string>DefaultHomeTab</string>
</ShowOn>
<Executable>
<FilePath>PowerShell.exe</FilePath>
-ExecutionPolicy RemoteSigned -File C:\PowerShell\CM12RClickTools\PromoteSIMToProd.ps1 "##SUB:DeploymentID##" "##SUB:__Server##" "##SUB:__Namespace##" "##SUB:CollectionID##"
</Executable>
</ActionDescription>

Notice in the .xml that we specify the -ExeuctionPolicy RemoteSigned parameter. Best practice would be to sign your scripts, but if that’s not something you can manage easily, you can use the parameter as shown to modify the execution policy for the specific instance you’re launching, instead of changing the execution policy for all script execution. Next, copy the PowerShell code below, and save it to C:\PowerShell\CM12RClickTools\PromoteSIMToProd.ps1

#capturing arguments:
$DeploymentID = $args[0]
$SiteServer = $args[1]
$SiteNamespace = $args[2]
$SiteCode = ($args[2]).Substring(14)
$CollectionID = $args[3]
$SiteDrive = $sitecode + ":"

#"{0}, {1}, {2}, {3}, {4}, {5}" -f $DeploymentID, $SiteServer, $SiteNamespace, $CollectionID, $Sitecode, $siteDrive

#setting a hard avail time and deadline of 20:00 on the same day the script is run.
##$availDate = read-host "Enter deadline date (e.g., 12/02/1973)"
#$availableTime = read-host "Enter deadline Time (e.g., 18:00 for 6:00pm)"
$availDate = (get-date).toshortdatestring()
$availtime = "20:00"  # if you want to configure for current time, (use get-date -format H:mm)
$deadlineDate = (get-date).toshortdatestring() #to specify a time in the future, just enter a date string like "12/02/2023" (with quotes)
$deadlineTime = "20:00"

"Querying Simulation Information..."
#Connect to PowerShell Provider:
$ModulePath = $Env:SMS_ADMIN_UI_PATH.Replace(„\bin\i386“,“\bin\ConfigurationManager.psd1“)

import-module $modulePath -force
if ((get-psdrive $siteCode -erroraction SilentlyContinue | measure).Count -ne 1) {
new-psdrive -Name $siteCode -PSProvider "AdminUI.PS.Provider\CMSite" -Root $SiteServer
}
cd $siteDrive

#"{0},{1}" -f $Coll.name.tostring(), $Coll.membercount.Tostring()

"Get Simulation Deployment Info"
$simDeploy = get-cmdeployment -deploymentid $DeploymentID
if ($simDeploy.DeploymentIntent -ne 3) {
"`nOnly Simulations can be Promoted to active deployments!`n"
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
break
}
$simDeploy

#Get Collection info, so we can show potential number of systems impacted
#    (for some reason, get-cmdevicecollection wasn't dispalying membercount consistently through script)
$Filter = "CollectionID='$CollectionID'"
$Coll = gwmi sms_collection -Namespace $SiteNamespace -ComputerName $SiteServer -filter $filter

#Display info to admin before proceeding.
"`nAvailable: {0}, {1}" -f $availdate, $availtime
"Deadline: {0}, {1}" -f $deadlineDate, $deadlineTime
"Collection: {0}" -f $Coll.Name
"Total Collection members: {0}" -f $Coll.membercount

#Prompt user to verify available and deadline times, and to confirm required deployment
$x = read-host ("Press [CTRL+C] to exit, or Press any key to create the required deployment ...")

"Promoting Simulation to Production..."

"Removing Simulation..."
remove-cmdeployment -ApplicationName $SimDeploy.SoftwareName -DeploymentID $simDeploy.DeploymentID -force
"Creating new Application Deployment"
Start-CMApplicationDeployment -CollectionName $simDeploy.CollectionName -Name $SimDeploy.SoftwareName  -AvaliableDate $availDate -AvaliableTime $availTime -Comment "Simulation Promoted to Production by $env:Username" -DeadlineDate $deadlineDate -DeadlineTime $deadlineTime -DeployAction Install -DeployPurpose Required -EnableMomAlert $True -PreDeploy $True -RaiseMomAlertsOnFailure $True -UserNotification DisplaySoftwareCenterOnly

Write-Host "Complete. Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

Now re-launch your ConfigMgr Admin console to use the new r-click->Promote Simulation to Production feature. As you can see from the code, we use Get-CMDeployment to obtain the details of the simulation – and we verify it’s a simulation by DeploymentIntent=3. We then perform a WMI query to get information on the targeted collection, so that we can show the admin the total collection member count. After prompting the admin to continue, we simply call Remove-CMDeployment to remove the simulation, and then use the information previously queried and call Start-CMApplicationDeployment to deploy the application. Include additional parameters for Start-CMApplicationDeployment to standardize the deployments for your environment. For example, you could add -RaiseMomAlertsOnFailure $True -OverrideServiceWindow $True to the command line.

So as you can see, this could be a huge opportunity to ensure a consistent, automated process for application deployment.

Happy Scripting!

Greg
ramseyg@hotmail.com