Distribution Point Migration Tool-Kit

, , , , , , , , , , ,
The Distribution Point Migration 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 Point, 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 Point, 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 of Distribution Point Migration Tool-kit

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


                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.

Importing drivers into SCCM in bulk

, , , , , ,

Importing SCCM drivers in bulk

This is taken from my TechNet gallery here: https://goo.gl/n1QT89

When you’re tasked with something like a Windows 10 upgrade, you’ll find yourself spending lots of time downloading and importing SCCM drivers.  While this script won’t go out and download them for you (like the Dell and HP Driver Import tools I’ve seen out there), it manufacturer, model, and architecture agnostic, you don’t get caught up trying to negotiate your way past your firewall and proxy teams, and it runs in a bit under 50 lines of code (including comments). Rather than pasting in the entire thing, I’ll do a screenshot and walk through from there.

sccm drivers

For this script to work, there’s some groundwork required on your part. When you download the drivers, they need to be downloaded into a folder that has whatever name you want for your driver package later.  If you’re like me, you’re already doing this as you download. If I need drivers for an HP Z230 desktop, the folder they’re saved in is already called “HP Z230 Windows 10 x64” or something similar so I can find them later.  The way this script works, whatever your folders’ names are is what names your driver packages will end up with.
Aside from that, all you need to do is plug in the path to the file share that has all your make/model folders in the root, as well as the location where you want to store your driver packages.
Something you will notice in this script is that I bounce between my C: drive and my SCCM drive. This is because UNC paths don’t always work as expected when you’re on the SCCM drive, and SCCM cmdlets don’t play nice running from anything other than the SCCM drive.  To guarantee they both work when needed, I just switch between locations, and it’s no big deal.
This script can take a little while to run, but it will give you feedback as it goes, and it doesn’t lock you out of the SCCM GUI while it runs.

SystemSettings.exe Crashes windows 10

, , ,


Recreate problem: Start > Settings > Accounts = crashes
Event Viewer shows the following error:

Faulting application name: SystemSettings.exe, version: 10.0.14393.82, time stamp: 0x57a55dc6
Faulting module name: usercpl.dll, version: 10.0.14393.1198, time stamp: 0x590280e6
Exception code: 0xc0000005
Fault offset: 0x000000000000d337
Faulting process id: 0x31e0
Faulting application start time: 0x01d2fffc16cd4baf
Faulting application path: C:WINDOWSImmersiveControlPanelSystemSettings.exe
Faulting module path: C:WINDOWSSystem32usercpl.dll
Report Id: 34a5a1ac-6e28-468d-b57d-f88e297b6f83
Faulting package full name: windows.immersivecontrolpanel_6.2.0.0_neutral_neutral_cw5n1h2txyewy
Faulting package-relative application ID: microsoft.windows.immersivecontrolpanel
What we see is the process “SystemSettings.exe” experiences a bugcheck  0xc0000005 when trying to access accounts.
Desired Outcome:




Initial Testing:


Remove security apps – same results
Created new vanilla Wim – same results
Remove from domain – works successful


Testing Next Steps:
Start blocking my test system from individual GPOs.
I was later pinpoint the exact GPO that was the cause of the problem. We have a rather lengthy security GPO in this environment that I inherited.


Deeper Troubleshooting:
everything in the GPO looked acceptable to me upon initial inspection. I next downloaded promon to get a trace of all the registry and file system activity of the process 
ProcDump Troubleshooting:
1.     Open command prompt as administrator
2.     Type “procdump.exe -ma -e -t systemsettings.exe”
3.     Reproduce the issue
4.     analyze the dump files.



Debug Notes:



Dump Name: systemsettings.exe_170801_094202.dmp
Computer Name: P974522
Windows 10 Version 15063 MP (4 procs) Free x64
Product: WinNt, suite: SingleUserTS
Debug session time: Tue Aug  1 10:42:02.000 2017 (UTC – 4:00)
System Uptime: 3 days 23:01:11.214
Process Uptime: 0 days 0:00:02.000
  Kernel time: 0 days 0:00:00.000
  User time: 0 days 0:00:00.000
User Name: H93
PID: 0x2698 = 0n9880
Comment: ‘
*** “C:UsersH93DesktopProcdumpprocdump.exe” -accepteula -ma -j “C:Dumps” 9880 360 00000284D63B0000
*** Just-In-Time debugger. PID: 9880 Event Handle: 360 JIT Context: .jdinfo 0x284d63b0000′
User Mini Dump File with Full Memory: Only application data is available.
CONTEXT:  (.ecxr)
rax=00000000ffffffff rbx=00000284d5b0b930 rcx=00000284d86188f8
rdx=0000000000000020 rsi=0000000000000000 rdi=ffffffffffffffff
rip=00007ff9d86f8a3f rsp=000000cda4efe270 rbp=000000cda4efe2c0
r8=0000000000000000  r9=0000000000000006 r10=00000fff44e562aa
r11=0451044040040500 r12=0000000000000000 r13=000000cda4efe920
r14=0000000000000000 r15=0000000000000001
iopl=0         nv up ei ng nz ac po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010296
00007ff9`d86f8a3f 488364c35000    and     qword ptr [rbx+rax*8+50h],0 ds:0000028c`d5b0b978=????????????????
Resetting default scope
ExceptionAddress: 00007ff9d86f8a3f (usercpl!CUserManager::_RemoveGuestTile+0x000000000000005b)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000001
   Parameter[1]: 0000028cd5b0b978
Attempt to write to address 0000028cd5b0b978
0:043> k
Child-SP          RetAddr           Call Site
000000cd`a4efc918 00007ffa`3309dd20 ntdll!ZwWaitForMultipleObjects+0x14
000000cd`a4efc920 00007ffa`3309dc1e KERNELBASE!WaitForMultipleObjectsEx+0xf0
000000cd`a4efcc20 00007ffa`332a191c KERNELBASE!WaitForMultipleObjects+0xe
000000cd`a4efcc60 00007ffa`332a142f kernel32!WerpReportFaultInternal+0x4bc
000000cd`a4efd210 00007ffa`33056a6f kernel32!WerpReportFault+0x73
000000cd`a4efd250 00007ffa`3354da9d KERNELBASE!UnhandledExceptionFilter+0x2af
(Inline Function) ——–`——– ntdll!RtlpThreadExceptionFilter+0x27
000000cd`a4efd360 00007ffa`33536476 ntdll!RtlUserThreadStart$filt$0+0x38
000000cd`a4efd390 00007ffa`3354a08d ntdll!__C_specific_handler+0x96
000000cd`a4efd400 00007ffa`334b9c58 ntdll!RtlpExecuteHandlerForException+0xd
000000cd`a4efd430 00007ffa`3354910e ntdll!RtlDispatchException+0x368
000000cd`a4efdb40 00007ff9`d86f8a3f ntdll!KiUserExceptionDispatch+0x2e
000000cd`a4efe270 00007ff9`d86f8b7a usercpl!CUserManager::_RemoveGuestTile+0x5b
000000cd`a4efe2a0 00007ff9`d86f8dbe usercpl!CUserManager::_HandleGuestAccountTile+0x12a
000000cd`a4efe2e0 00007ff9`d870e739 usercpl!CUserManager::ResetUserData+0x1ce
000000cd`a4efe380 00007ffa`32f588d3 usercpl!CUserManagementWizards::GetUserManagerInstance+0x129
000000cd`a4efe450 00007ffa`32fbc93e rpcrt4!Invoke+0x73
000000cd`a4efe4a0 00007ffa`32ef91a4 rpcrt4!Ndr64StubWorker+0xbde
000000cd`a4efeb70 00007ffa`327c4d99 rpcrt4!NdrStubCall3+0xb4
000000cd`a4efebd0 00007ffa`32f43a2b combase!CStdStubBuffer_Invoke+0x59
000000cd`a4efec10 00007ffa`32867963 rpcrt4!CStdStubBuffer_Invoke+0x3b
(Inline Function) ——–`——– combase!InvokeStubWithExceptionPolicyAndTracing::__l6::<lambda_76d9e92c799d246a4afbe64a2bf5673d>::operator()+0x2b
000000cd`a4efec40 00007ffa`32866286 combase!ObjectMethodExceptionHandlingAction<<lambda_76d9e92c799d246a4afbe64a2bf5673d> >+0x53
(Inline Function) ——–`——– combase!InvokeStubWithExceptionPolicyAndTracing+0x89
000000cd`a4efeca0 00007ffa`3286c75e combase!DefaultStubInvoke+0x216
(Inline Function) ——–`——– combase!SyncStubCall::Invoke+0x2c
(Inline Function) ——–`——– combase!SyncServerCall::StubInvoke+0x2c
(Inline Function) ——–`——– combase!StubInvoke+0x290
000000cd`a4efeeb0 00007ffa`328683ff combase!ServerCall::ContextInvoke+0x45e
(Inline Function) ——–`——– combase!CServerChannel::ContextInvoke+0x97
(Inline Function) ——–`——– combase!DefaultInvokeInApartment+0xb0
(Inline Function) ——–`——– combase!ClassicSTAInvokeInApartment+0x1e6
000000cd`a4eff190 00007ffa`328648aa combase!AppInvoke+0xa5f
000000cd`a4eff300 00007ffa`32803369 combase!ComInvokeWithLockAndIPID+0x57a
(Inline Function) ——–`——– combase!ComInvoke+0x1c0
000000cd`a4eff580 00007ffa`32802fe8 combase!ThreadDispatch+0x2b9
000000cd`a4eff650 00007ffa`3335bc50 combase!ThreadWndProc+0x198
000000cd`a4eff6f0 00007ffa`3335b5cf user32!UserCallWinProcCheckWow+0x280
000000cd`a4eff850 00007ff9`d870d2dc user32!DispatchMessageWorker+0x19f
(Inline Function) ——–`——– usercpl!Windows::Internal::ComTaskPool::CThread::_DispatchMessage+0x1a
000000cd`a4eff8d0 00007ff9`d870d761 usercpl!Windows::Internal::ComTaskPool::CThread::_WaitForThreadUpdate+0x70
000000cd`a4eff940 00007ff9`d870d13e usercpl!Windows::Internal::ComTaskPool::CThread::_ThreadProc+0x37d
000000cd`a4effa00 00007ff9`d870d259 usercpl!Windows::Internal::ComTaskPool::CThread::s_ExecuteThreadProc+0x12
000000cd`a4effa30 00007ffa`332b2774 usercpl!Windows::Internal::ComTaskPool::CThread::s_ThreadProc+0x9
000000cd`a4effa60 00007ffa`33510d61 kernel32!BaseThreadInitThunk+0x14
000000cd`a4effa90 00000000`00000000 ntdll!RtlUserThreadStart+0x21
0:043> .f-
0c 000000cd`a4efe270 00007ff9`d86f8b7a usercpl!CUserManager::_RemoveGuestTile+0x5b
0:043> dv
           this = 0x00000284`d5b0b930
         iGuest = 0n-1             ß failed to locate the index of the Guest account
              i = 0xffffffff
GPO Looks like this (wrong)


Cause:  The systemsettings.exe crashed because it could not identify the index of the guest account while loading user information.  In our environment the guest account is renamed by GPO to something different. This crash can happen if the following two conditions are met:
1. The guest account is disabled ore renamed
2. The number of profiles stored under the following key is more than 100:
a. HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionProfileList
Resolution:  Renamed the “***Guest” account to “Guest” and left the account disabled in GPO and we get the expected functionality.