Tuesday, May 30, 2017

Tabulate OS Counts from Active Directory

For a couple smaller environments without ConfigMgr I wanted to know the versions of Windows, specifically the build # of Windows 10 so I knew counts of each version to target updates via WSUS or manually.

Over on the TechNet Gallery I found something that was real close written by Brian Arnold. The script will look at AD and count all OS versions and email it. I have this running on a monthly basis. Good "Executive Overview".

CountName
4Windows 10 Pro, 10.0 (10586)
3Windows 10 Pro, 10.0 (14393)
1Windows 2000 Professional, 5.0 (2195)
1Windows 7 Professional, 6.1 (7601)
1Windows 7 Ultimate, 6.1 (7601)
3Windows Server 2012 R2 Standard, 6.3 (9600)

I ended up modifying it a little as shown above. The bordering was not working right and I wanted to also get the version for Windows 10 in addition the friendly name. The script will spit to the console as well as email. I'm not that good with PS1 scripts so someone can do way better then my attempt. All credit to Brian.

The scheduled task is pretty simple:

 powershell.exe -ExecutionPolicy Bypass "Path\To\\CountOS\Get-OSCounts.ps1"  


Download

This script is provided as-is, no warranty is provided or implied.The author is NOT responsible for any damages or data loss that may occur through the use of this script.  Always test, test, test before rolling anything into a production environment.

You can obtain my modified version here.

Tuesday, April 25, 2017

Publish Exchange Online Calendar to Android

As with many firms out there, mobile devices fall into a BYOD strategy so I have come to really like the Outlook app for Android as it "containerizes" my work email. Over the years, I have tried them all from Touchdown to Boxer (formally Enhanced Email) and settled on Outlook currently. However they generally use ActiveSync so any security rules ActiveSync enables can take over the device. It is MY device, not my firms.

With that said though, unlike many people I use my work calendar for work related entries and my personal Google calendar (hosted on G Suite) for personal stuff, Android pulls from there. So my work calendar will just show a PTO block (marked out of office) for that appointment time (plus travel and what not) and my personal calendar shows all the details. Keeps things nice and separated.

The problem is that I live out of my mobile device so one thing I am challenged by using the Outlook app, is the calendar. While Outlook publishes contacts to the phone, that is all, nothing else. Strangely the old Outlook.com app would publish the calendar to the system though. I use and love a fantastic app app called Business Calendar Pro to manage all my calendars as well as give me one pane of glass via its widgets. All color coded and pretty.

On my Moto X (2014) I had both Outlook and Boxer syncing which means Boxer uses ActiveSync so it took over my phone but I got the calendar for my single pane as a compromise. Ick but I lived with it until recently when Samsung gave me a shiny new Galaxy S8 to use for a bit so I thought I would set it up differently, especially now that we have migrated to Exchange Online via Office365.

Sure enough there is a useful option out there, as long as your Office365 admin does not disable it, called Calendar Sharing. Very easy to setup though the process may change as Microsoft does change the Office365 online experience but as of this writing it is quick and easy.

Share Process


1. Access your Calendar via one of several methods:


2. Click the gear icon in upper right



3. Under Your App Settings, select Calendar


4. On the left choose Calendar publishing


5. Configure permissions by choosing either 'Full Details' or 'Limited Details'. The difference is Limited only shows day/time whereas full shows everything in the body such as Skype dial in info. Click Save when done.


6. Copy the ICS link a tthe bottom as you'll need it later.

7. Navigate over to your Google Calendar and on the left you will find Other Calendars. Hover over it and click the down arrow and choose Add by URL then paste the URL from step 6.


Now you have your Exchange Online calendar present in Google Calendar as Read Only. You can select the down arrow and rename, change the color etc. I have mine turned off on the web calendar as I only want it on my phone. Additionally I renamed to my company.


8. After your phone does its next sync, goto your favorite calendar app (mine being Business Calendar Pro) on your phone and enable the calendar. Bam! There it is.

Two things to point out again.


  1. This feature can be disabled by your Office365 Admin(s)
  2. It is read only
Since Outlook Online Calendar publishes as ICS or HTML you can use in other solutions as well.







Tuesday, April 18, 2017

Unhandled Exception Using Task Sequence Wizard to create Upgrade Task Sequence

Ever since the in-place Task Sequence was made available in 1511 I have been unable to create one via the wizard as I get this fun error:


Every other one worked, just not the upgrade (in-place) one. I usually create them from scratch so went that route and tabled getting this fixed. Originally I thought it may be a bug thats resolved in a newer release such as 1602 or 1606 so I checked again after upgrading to each of these versions. Received the same error so nope still broke, so once upgrade to 1606 we put in a Premier ticket over it with Microsoft.

They also thought it was a back-end issue so we provided dump after dump and log to no resolution. Once we were ready to upgrade to 1610 we tabled the ticket until that was complete. After 1610 the problem was still present so more dumps and logs submitted. Finally, Microsoft Support came back and had us uninstall and reinstall the console on the primary server. Fixed! In turn we reinstalled the console on the workstation systems it was installed on as well and those were fixed.

So this problem was NOT with the back-end infrastructure but with the local console install itself. All of our consoles were automatically upgraded whenever we upgraded ConfigMgr versions. Perhaps there is a bad DLL or other support file thats corrupt or not updated during a console update? Who knows. I may look into it some day to understand it. The fix is easy though.

So if you see an error like this, just re-install your console. Many ways to do this so take your pick. One way is via an elevated command prompt and navigate to the primary servers install folder, generally located at '\\SCCMServer\SMS_xxx\Tools\ConsoleSetup'


 pushd \\SCCMServer\SMS_xxx\Tools\ConsoleSetup  
 consolesetup.exe /uninstall /q   

PUSHD is a nice command to quickly mount a UNC path using your rights if you didn't know. Additionally, you can skip the /q switch to use the wizard. Once that is done delete the install folder which is generally located at %ProgramFiles(x86)%\Microsoft Configuration Manager. 

 consolesetup.exe /install  
 POPD  

You can remove the /install switch so it runs the wizard. POPD will unmount the share.

In my case I also have 1E Nomad so I had to do a repair via Programs and Features for '1E Nomad Branch Admin Extensions 2012'. Easy fix to a long term problem.

-Kevin





Monday, March 27, 2017

Office 365 Click-to-Run Updates via ConfigMgr ADR

I have shared in the past how I am deploying Office 365 Click-to-Run (C2R) updates via ConfigMgr and DFS namespaces. Works fine, however now that C2R 2016 has settled into ConfigMgr handling updates, Iam transitioning to that.

Following the proverbial 80/20 rule, the majority of my fleet receives the Deferred Channel for Office365 Click-to-run 2016 same as most companies have chosen. For the other 20 percent they will have a mix of the remaining channels. We have decided that these other channels will be opt in for those proactive users wanting features quicker then the Deferred Channel cadence provides as well as provide SME (Subject Matter Experts) early access for testing their plug-ins etc.

The main parts of the past articles are still in place. We use AD Groups to house the users that get these other channels which is referenced by an SCCM collection for advertisements.

While we do patches on a monthly cycle, there are many times these other Office channel updates will be released outside of that, especially around First Release for Current and Current channels so we have chosen to use ADRs to automate their release so we can be nearly hands off.

First thing is to setup the ADR by navigating to \Software Library\Overview\Software Updates\Automatic Deployment Rules. Prajwal Desai covers a step by step ADR creation so I will only point out C2R specifics here:

General

On the general tab. I chose to save to an existing Software Update Group (SUG). This way you have just one SUG and one package per Channel. Note that if YOU create a SUG, it will create another one on its first run and use the one it created subsequently.


Deployment Settings



Software Updates

For this tab I chose the following properties to pivot off of.

  • Date Released or Revisited = 'Last 1 month'
  • Product = 'Office 365 Client'
  • Title = 'Office 365 Client Update - First Release for Current Channel'


Definitely select the Preview tab so you make sure you are getting the results you expected. In this example below, this is the last month as the rule calls out. It pulls back 6 entries, which are 3 versions with both arches. As I have both 32-bit and 64-bit I do not need to split those at this time, however I may split the arches out down the road to keep packages smaller as 64-Bit C2R has a very small footprint so I can keep it closer to the core since its not in use that much compared to 32-Bit C2R.



Evaluation Schedule

Check for updates after the SUP synchronizes.


Deployment Package

I use an existing package so each channel stays in one easy to manage SUG and package. This does mean that the package will update on its own instead of controlled by admins. Each office release is a little over 1GB in size, double for both arches.



On a related note, I use 1E Nomad for (client package) replication, the first release packages are only on my two main DPs in the main site with the Current Channel being at all DPs and clients pull from them. First release channels are on a few clients at this point and are not expected to grow past a few hundred. I see no need to have these files hosted at every site via Nomad since I may not have clients with these Channels there. So the faster channel clients do pull the content slowly across the wire. As they grow we can move them out more or bring them back in from a distribution standpoint.


Completed

Once done I have 3 rules setup for the automatic updates for the bleeding edge folks.


The Software Groups are nice and clean also. I have the 3 ADRs and the one manual for Deferred Channel that is created on our monthly cycle.


Maintenance

Depending on how you have your SUP supercedence set up you may have to do some maintenance and clean out old updates from the SUG so they are removed from the package by ConfigMgr. Our process is to do it when we do our monthly patch workflow however the supercedence can remove them on its own.

-Kevin








Friday, March 10, 2017

1E NomadBranch Collections

I'm working on updating our 1E NomadBranch install to the latest version and thought having some collections for it would be useful. We already have many for ConfigMgr itself.


So for Nomad Activity I set up these collections as I thought they would be useful for the upgrade but also ongoing.


To start I have a parent collection called 'All Systems with 1E NomadBranch' I used this for the query.

 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_ADD_REMOVE_PROGRAMS on SMS_G_System_ADD_REMOVE_PROGRAMS.ResourceID = SMS_R_System.ResourceId inner join SMS_G_System_ADD_REMOVE_PROGRAMS_64 on SMS_G_System_ADD_REMOVE_PROGRAMS_64.ResourceID = SMS_R_System.ResourceId where SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName like "1E Nomad%" OR SMS_G_System_ADD_REMOVE_PROGRAMS_64.DisplayName like "1E Nomad%"  

I ended up using the % wildcard as version 6 is called 'NomadBranch' and version 5 is called 'Nomad Branch' (has space). This was easier then doing separate queries or other ways. Additionally Nomad has both 32-Bit and 64-Bit so we pull from SMS_G_System_ADD_REMOVE_PROGRAMS_64.DisplayName and SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName as well.

Now we break down the major versions. I'm a fan of parent/child collections so these are limited to the parent collection 'All Systems with 1E NomadBranch' above. We obtained NomadBranch at version 5.2 so I didn't do anything earlier then that. For these I ended up just looking for the version of NomadBranch.EXE.

All Systems with 1E NomadBranch 6

 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_SoftwareFile on SMS_G_System_SoftwareFile.ResourceID = SMS_R_System.ResourceId where SMS_G_System_SoftwareFile.FileName = "NomadBranch.exe" and SMS_G_System_SoftwareFile.FileVersion like "6.%"  


All Systems with 1E NomadBranch 5
 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_SoftwareFile on SMS_G_System_SoftwareFile.ResourceID = SMS_R_System.ResourceId where SMS_G_System_SoftwareFile.FileName = "NomadBranch.exe" and SMS_G_System_SoftwareFile.FileVersion like "5.%"  

I also wanted sub versions so I created those also. I didn't know I had any version 5 so they are getting updated forcefully. With that said, I didn't care to expand those out and focus on 6 since its the current major version. So we look for version 6.0 and 6.1. These are limited to the main version 6.

All Systems with 1E NomadBranch 6.0
 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_SoftwareFile on SMS_G_System_SoftwareFile.ResourceID = SMS_R_System.ResourceId where SMS_G_System_SoftwareFile.FileName = "NomadBranch.exe" and SMS_G_System_SoftwareFile.FileVersion like "6.0%"  

All Systems with 1E NomadBranch 6.1
 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_SoftwareFile on SMS_G_System_SoftwareFile.ResourceID = SMS_R_System.ResourceId where SMS_G_System_SoftwareFile.FileName = "NomadBranch.exe" and SMS_G_System_SoftwareFile.FileVersion like "6.1%"  

For all the above versions, they are the same query with the version number changed so copying makes it quicker. A like is used since version is a string vs using a full match as Nomad uses X.X.X.X version structure and we have many sub versions around.

Finally, I wanted to know who was NOT on the latest patch level. At the time of this post it is 6.1.100.181. So we use the same query but use a ≠ (not equals) instead of a like for the version. As new patches come out we just modify this query so we can target any upgrades needed.

All Systems with 1E NomadBranch 6.1 NOT Current Patch
 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_SoftwareFile on SMS_G_System_SoftwareFile.ResourceID = SMS_R_System.ResourceId where SMS_G_System_SoftwareFile.FileName = "NomadBranch.exe" and SMS_G_System_SoftwareFile.FileVersion != "6.1.100.181"  

As a bonus I also wanted to know who had the 1E ConfigMgr Extensions installed. This is limited to a collection of who has the SCCM Console installed.

All Systems with 1E NomadBranch Admin Extensions
 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_ADD_REMOVE_PROGRAMS on SMS_G_System_ADD_REMOVE_PROGRAMS.ResourceID = SMS_R_System.ResourceId where SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName = "1E Nomad Branch Admin Extensions 2012"  


And who needs to be updated

All Systems with 1E NomadBranch Admin Extensions less then 6.1
 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_ADD_REMOVE_PROGRAMS on SMS_G_System_ADD_REMOVE_PROGRAMS.ResourceID = SMS_R_System.ResourceId where SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName = "1E Nomad Branch Admin Extensions 2012"  


-Kevin

Wednesday, February 22, 2017

Windows 10 In-Place Upgrade Assessment Error Handling



As I progress to making Windows 10 available to end users I needed to polish out the error handling. While I am using the Upgrade Readiness tool that Microsoft provides to target successful systems, I am still performing one final check in the Task Sequence by having the Task Sequence do an assessment before continuing and capturing those results.

You just insert the Upgrade Operating System step and select the box 'Perform Windows Setup compatibility scan without starting upgrade' at minimum. I have also selected the other chekboxes below it such as 'Ignore any dismissible compatibility messages' checkbox. If unchecked, this will for example, trigger a failure for an incompatible driver that gets removed anyway. Useful if you have some weird driver for a microscope type device (I do!) but not useful if you accept the removal that the upgrade does. For those types of endpoints the Readiness tool has identified them.



I also enabled the last two check boxes. These will cause the eval step to pull the latest eval info from Microsoft instead of using what data shipped on the ISO. There may be some proxy concerns here.

Here is what that part of the Task Sequence looks like:



For initial roll out to IT, I am using Niall C. Brady's dialog Powershell Script so I wont cover that part here. I am working on a template script to pull HTML edited file to be more polished for an end user when I get to that point but Niall's script works great.

The 'Upgrade Assessment' step outputs to the read-only variable _SMSTSOSUpgradeActionReturnCode. SETUP.EXE actually outputs in hex whereas the variable is in decimal. Looking at Microsofts blog post these are the major exit codes. I converted the hex to decimal with a converter so I work in the same format ConfigMgr is.


  • No issues found:  0xC1900210 (3247440400)
  • Compatibility issues found (hard block):  0xC1900208 (3247440392)
  • Migration choice (auto upgrade) not available (probably the wrong SKU or architecture)· 0xC1900204 (3247440388)
  • Does not meet system requirements for Windows 10: 0xC1900200  (3247440384)
  • Insufficient free disk space: 0xC190020E (3247440398)


The 'Assessment Errors Detected' group has a condition of _SMSTSOSUpgradeActionReturnCode ≠ 3247440400 whereas the 'Upgrade the Operating System' group has _SMSTSOSUpgradeActionReturnCode = 3247440400.

Under the 'Assessment Errors Detected' Group, each of the 4 sub groups matches a code in _SMSTSOSUpgradeActionReturnCode. For example, the 'Compatibility Issues found (hard block)' group has a condition for _SMSTSOSUpgradeActionReturnCode = 3247440392.

Then each error code displays a custom message and errors the Task Sequence out. For the  'Compatibility Issues found (hard block)' error it shows

The Upgrade Assessment detected an error which is preventing a successful upgrade and it must be mitigated first. There is an application or driver that must be removed first. This is generally due to an old version of Sophos Safeguard present. Please contact the IT Service Desk for assistance.

Again, these groups are just a final sanity check, While the Readiness tool identifies bullet 2 impacted systems, ConfigMgr collections are identifying the last two bullets for example.

-Kevin


Monday, February 13, 2017

Replace Edge with Internet Explorer on Windows 10 (1607) via Task Sequence (Part II)

My most popular post is how I replaced Edge with IE in Windows 10. Since then, Microsoft made it a substantially easier in version 1607 to do this. IE is still a little wonky though as you'll see. I was able to take it down to two steps. Just the 'customize Start' and 'Copy IE Shortcut to Default Profile' steps. All the highlighted steps were removed and not needed anymore





I'll cover below as it could just be one step depending on your environment. My previous post is still worth a read as I wont rehash parts of it here and it covers some of the mechanics that still apply in 1607.

So what changed? Microsoft expanded how you can modify via the Export-StartLayout and Import-StartLayout PowerShell cmdlets. They have a good article about it here.

Task Bar


For the startbar modification I took the sample from the Technet article and added in the paths to the shortcuts so they get pinned (bolded below). There are some places you will NOT be able to point to such as %PROGRAMDATA% but know that %ALLUSERSPROFILE% points to the same location by default.

Additionally, you can append or replace based on the PinListPlacement element.

 <?xml version="1.0" encoding="utf-8"?>  
 <LayoutModificationTemplate  
   xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"  
   xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"  
   xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"  
   xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"  
   Version="1">  
  <CustomTaskbarLayoutCollection PinListPlacement="Replace">  
   <defaultlayout:TaskbarLayout>  
    <taskbar:TaskbarPinList>  
     <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Accessories\Internet Explorer.lnk" />  
     <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk" />  
     <taskbar:DesktopApp DesktopApplicationLinkPath="%ALLUSERSPROFILE%\Microsoft\Windows\Start Menu\Programs\Outlook 2016.lnk" />  
    </taskbar:TaskbarPinList>  
   </defaultlayout:TaskbarLayout>  
  </CustomTaskbarLayoutCollection>  
 </LayoutModificationTemplate>  

As the Technet article states, if you are unsure of the path you can pin it to the start menu and export it to get the path then put that under the taskbar section.

Taskbar is done and tested and was the whole fight in my last article. Way better right? Now onto the Start Menu.

Start Menu


For the Start Menu I setup a clean machine and organized it how I wanted and then exported it via the PowerShell cmdlet.

 Export-StartLayout \\server\path\to\LayoutModification.XML  

In my task sequence I then imported each XML but only the Taskbar was changed. Turns out you can only import ONE XML that manipulates the default desktop. So I had to merge them into one file. I split them thinking we may have a need to modify one over the other and since the Taskbar was imported second it trumped the Start Menu XML.

Heres the bonkers part. The IE shortcut for the Start Menu. This is how I learned that it does not honor %PROGRAMDATA% path to items. You are stuck in the majority to %ALLUSERSPROFILE% and %APPDATA% variable paths.

for my taskbar I am using "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Accessories\Internet Explorer.lnk" so I referenced that as well for the Start Menu section. Nope, does not work. %APPDATA% points to your roaming profile. My suspicion is that the Start menu is created a little earlier in the initial login process so it shows up blank due to the legacy profile paths are not created yet.

According to this MSDN article that f you are pointing to a third-party Classic Windows application, you must put the .lnk file in a legacy Start Menu directory before first boot. For example, "%APPDATA%\Microsoft\Windows\Start Menu\Programs\" or the all users profile located at"%ALLUSERSPROFILE%\Microsoft\Windows\Start Menu\Programs\". IE falls under this.

With that said though, I am able to point to the IE executable under %PROGRAMFILES%  and use this in the XML

 <start:DesktopApplicationTile Size="1x1" Column="0" Row="0" DesktopApplicationLinkPath="%PROGRAMFILES%\Internet Explorer\iexplore.exe" />  

It works, but ONLY for the first user to login. I think Windows modifies the imported XML to update it to %APPDATA%, which if you do an export right after login it reflects this.

 <start:DesktopApplicationTile Size="1x1" Column="0" Row="0" DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Accessories\Internet Explorer.lnk" />  

So on subsequent users logging in they do not get this icon. The first user is fine through all their logins. As many of my firms machines are used by multiple users, I decided to just copy the IE shortcut and point to that in my XML. As all the office shortcuts are put under "%ALLUSERSPROFILE%\Microsoft\Windows\Start Menu\Programs" I just put the IE shortcut there. If you do not want to pin IE to the Start Menu then this is not needed. I have it pinned to both the Task Bar and Start Menu. For the Task Bar I could change to this precopied one or leave as is in the users profile.

Task Sequence


For the task sequence I just have two steps. The 'Customize Start' step is a PowerShell step that calls 'Configure-StartMenu.ps1' that just contains

 Import-StartLayout -LayoutPath .\LayoutModification.xml -MountPath $env:SystemDrive\  

The 'Copy IE shortcut to default profile' step simply copies the file from the package to the default users start.

 xcopy "Internet Explorer.lnk" "%ALLUSERSPROFILE%\Microsoft\Windows\Start Menu\Programs" /E /C /I /H /Y  

I was done! Now that i know about the path issue for IE, the default Start can be updated within a few minutes.



Upon doing some final bare metal VM deployments, I noticed that a Start Menu shortcut for FireFox was missing. Who do we use during deployment? BUILTIN\SYSTEM. This makes me think further that the custom Start Menu is generated at login of ANY user after importation but not applied to an existing user. So by moving the 'Customize Start' step towards the end of the Task Sequence, this was resolved as it ran AFTER applications that are pinned to the Start Menu are installed, like FireFox.

-Kevin






Thursday, February 9, 2017

Update OneDrive Next Gen Sync agent during Windows 10 Deployment


For my environment, the OneDrive Next gen sync agent is installed by Office 2016 Click-to-Run as it still Windows 7 for the majority. For the Windows 10 systems however its included in the OS and even with 1607 is now out of date. Instead of letting it update after deployment and presenting dialogs to the user, I thought I would update it via the deployment Task Sequence so its current right out of the box.

I chose to handle this via a simple BAT file thats really just 3 lines thats needed. Windows 10 keeps the OneDriveSetup.EXE  in %WINDIR%\SysWOW64 folder on 64-Bit systems and %WINDIR%\SYSTEM32 on 32-Bit. It is a 32-bit application so the File System Redirector handles how its presented. So first we need to find the file. Note that the Office install puts it under Program Files(x86)\OneDrive.

 IF EXIST %SYSTEMROOT%\System32\OneDriveSetup.exe SET ONEDRIVEPATH=%SYSTMEROOT%\System32\OneDriveSetup.exe  
 IF EXIST %SYSTEMROOT%\SysWOW64\OneDriveSetup.exe SET ONEDRIVEPATH=%SYSTEMROOT%\SysWow64\OneDriveSetup.exe  

Since the file is owned by BUILTIN\TrustedInstaller we have to take ownership so SCCM is able to replace it.

 %SYSTEMROOT%\system32\takeown.exe /f %ONEDRIVEPATH%  

Now that we own it, we can modify permissions. Since its ran during the TS we are running as BUILTIN\System so lets give that account Full rights to the file. This allows us to delete and replace it.

 %SYSTEMROOT%\system32\icacls.exe %ONEDRIVEPATH% /Grant System:(F)  

Then simply copy the newer one. If your doing manually outside of a TS step you should use '%~dp0' variable.

 Copy OneDriveSetup.exe %ONEDRIVEPATH%  

The entire script is below if you want to just use it as is.

 @ECHO OFF  
 :: from https://kevinisms.fason.org  
 :: written by Kevin Fason  
 :: This will take ownership of OneDriveSetup.exe for Windows 10 so we can update it  
 :: Version 1.0  
 ::  Initial Release  
 :: February 6, 2017  
 ::  
 :: Locate it due to system32/Syswow64 switching per what bitlevel this scrip runs in  
 IF EXIST %SYSTEMROOT%\System32\OneDriveSetup.exe SET ONEDRIVEPATH=%SYSTMEROOT%\System32\OneDriveSetup.exe  
 IF EXIST %SYSTEMROOT%\SysWOW64\OneDriveSetup.exe SET ONEDRIVEPATH=%SYSTEMROOT%\SysWow64\OneDriveSetup.exe  
 :: Make changes  
 :: Take Ownership  
 %SYSTEMROOT%\system32\takeown.exe /f %ONEDRIVEPATH%  
 :: Give BUILTIN\System Full rights  
 %SYSTEMROOT%\system32\icacls.exe %ONEDRIVEPATH% /Grant System:(F)  
 :: Replace the old one  
 Copy OneDriveSetup.exe %ONEDRIVEPATH%  

There are many other ways to handle something like this. Since this BAT is called from a wrapper there is zero checks and balances as the wrapper and ConfigMgr application handle that.  I chose an if then but you can use a goto statement as well for each bitlevel location. Doing it via Powershell is possible also however a BAT is alot simpler IMO. My co-worker Jason provided this as an example while still using built in executibles for the ownership and ACL work.

 $Path32 = $ENV:SYSTEMROOT + '\system32\OneDriveSetup.exe'  
 $Path64 = $ENV:SYSTEMROOT + '\syswow64\OneDriveSetup.exe'  
 if([System.IO.File]::Exists($path32))  
 {  
   [Environment]::SetEnvironmentVariable("ONEDRIVEPATH", $Path32, "Machine")  
   & c:/Windows/system32/takeown.exe /f $Path32  
   & c:/Windows/system32/icacls.exe $Path32 /Grant ("System" + ':F')  
 Copy-item ./OneDriveSetup.exe $Path32 -force   
   Write '32'  
 }  
 if([System.IO.File]::Exists($path64))  
 {  
   [Environment]::SetEnvironmentVariable("ONEDRIVEPATH", $Path64, "Machine")  
   & c:/Windows/system32/takeown.exe /f $Path64  
   & c:/Windows/system32/icacls.exe $Path64 /Grant ("System" + ':F')  
  Copy-item ./OneDriveSetup.exe $Path64 -force   
   Write '64'  
 }  



Tuesday, January 10, 2017

Windows 10 ConfigMgr Collections

I've been creating alot of Windows 10 focused collections in SCCM so thought I would gather what I have here. Mostly for me, but also to share with the world. I'll update as I add other ones and tweak these queries. If you have any share them with me!

The main one is to look for Windows 10 specifically. It should be pretty commonly known. I'm not one to use the 'All Systems' built-in collection so I have a parent called 'All Workstations' which contains all endpoints that are not Servers. I set the initial Windows 10 collection below to limit from that collection.

All Windows 10 Systems

 select SMS_R_System.ResourceID,SMS_R_System.ResourceType,SMS_R_System.Name,SMS_R_System.SMSUniqueIdentifier,SMS_R_System.ResourceDomainORWorkgroup,SMS_R_System.Client from SMS_R_System where OperatingSystemNameandVersion like '%Workstation 10.0%'  

Individual Versions. These all reference the above as the limiting collection. They are the same exception the version at the end.

All Windows 10 v1507 Workstations (10.0.10240)

 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.Build like '10.0.10240%'  

All Windows 10 v1511 Workstations (10.0.10586)

 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.Build like '10.0.10586%'  

All Windows 10 v1607 Workstations (10.0.14393)

 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.Build like '10.0.10586%'  

These show the branches. These are the same except for SMS_R_System.OSBranch difference.

All Windows 10 Current Branch (CB)

 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.OperatingSystemNameandVersion like '%Workstation 10.0%' and SMS_R_System.OSBranch = '0'  

All Windows 10 Current Branch for Business (CBB)

 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.OperatingSystemNameandVersion like '%Workstation 10.0%' and SMS_R_System.OSBranch = '1'  

All Windows 10 Long Term Service Branch (LTSB)

 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.OperatingSystemNameandVersion like '%Workstation 10.0%' and SMS_R_System.OSBranch = '2'  

These are neat ones. They show which ones that have expiring info around Servicing. They are all the same except SMS_WindowsServicingStates.State.

All Windows 10 Servicing Current

 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System LEFT OUTER JOIN SMS_WindowsServicingStates ON SMS_WindowsServicingStates.Build = SMS_R_System.build01 AND SMS_WindowsServicingStates.branch = SMS_R_System.osbranch01 where SMS_WindowsServicingStates.State = '2'  

All Windows 10 Servicing Expiring Soon

 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System LEFT OUTER JOIN SMS_WindowsServicingStates ON SMS_WindowsServicingStates.Build = SMS_R_System.build01 AND SMS_WindowsServicingStates.branch = SMS_R_System.osbranch01 where SMS_WindowsServicingStates.State = '3'  

All Windows 10 Servicing Expired


 select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System LEFT OUTER JOIN SMS_WindowsServicingStates ON SMS_WindowsServicingStates.Build = SMS_R_System.build01 AND SMS_WindowsServicingStates.branch = SMS_R_System.osbranch01 where SMS_WindowsServicingStates.State = '4'  

For Editions you can use these to capture Pro vs Enterprise etc. I dont use Education but it should be easy to adapt also.

All Windows 10 Enterprise Edition

 select distinct SMS_R_System.ResourceId, SMS_R_System.ResourceType, SMS_R_System.Name, SMS_R_System.SMSUniqueIdentifier, SMS_R_System.ResourceDomainORWorkgroup, SMS_R_System.Client from SMS_R_System inner join SMS_G_System_OPERATING_SYSTEM on SMS_G_System_OPERATING_SYSTEM.ResourceID = SMS_R_System.ResourceId where SMS_G_System_OPERATING_SYSTEM.Caption = "Microsoft Windows 10 Enterprise"  

All Windows 10 Pro Edition

 select distinct SMS_R_System.ResourceId, SMS_R_System.ResourceType, SMS_R_System.Name, SMS_R_System.SMSUniqueIdentifier, SMS_R_System.ResourceDomainORWorkgroup, SMS_R_System.Client from SMS_R_System inner join SMS_G_System_OPERATING_SYSTEM on SMS_G_System_OPERATING_SYSTEM.ResourceID = SMS_R_System.ResourceId where SMS_G_System_OPERATING_SYSTEM.Caption = "Microsoft Windows 10 Pro"  

For the Insider Preview versions I'm still figuring out a nice query for it. In the mean time. I just created a collection that is limited to the initial Windows 10 collection. It in turn has an include for the same Windows 10 collection and excludes for the versions above. (1507, 1511, and 1607 currently). When the Creators Update is released its version would need to be added as an exclusion.

Everything above uses the initial Windows 10 collection as limiting. Once any useful ones are created , you can have all sorts of fun by taking the initial query above and using other limiting collections such as bit-level (64-bit vs 32-bit), or platforms like mobile vs desktop or Dell, Lenovo, and what not to isolate further.

Then of course there is Windows 2016

 select SMS_R_System.ResourceID,SMS_R_System.ResourceType,SMS_R_System.Name,SMS_R_System.SMSUniqueIdentifier,SMS_R_System.ResourceDomainORWorkgroup,SMS_R_System.Client from SMS_R_System where OperatingSystemNameandVersion like '%Server 10%'