The Error Message That Wasted Part Of My Day – or – I Am Not A Smart Man…

, , , , , , ,

The Error Message That Wasted Part Of My Day – or – I Am Not A Smart Man…

I’ve run into an issue that I couldn’t find documented anywhere, so I am hoping this post can help someone else in the future.

I recently stood up a new environment for a school district and it’s running ConfigMgr 1902 with ADK 1903. I prefer to have a custom boot image that is separate from the default boot images that are created with the set-up. Because I don’t want to risk breaking a boot image during an upgrade of ConfigMgr/ADK in the future. So, I open the Deployment and Imaging Tools Environment cmd prompt and run:

copype.cmd amd64 c:\bootimagex64

I take the boot.wim file from c:\bootimagex64\media\sources and place it in my site server sources folder for import. I go to Software Library -> Operating Systems -> Boot Images, select Add Boot Image, type out the UNC path to my site server sources folder and the new boot.wim file. Easy Peasy … but then I’m presented with the following error message:

The specified UNC path does not contain a valid boot image file or you do not have permission to access it. Specify a valid path.

The specified UNC path does not contain a valid boot image file or you do not have permission to access it. Specify a valid path.

The path IS valid! The Add Boot Image Wizard even completes my UNC path as I type it …

The specified UNC path does not contain a valid boot image file or you do not have permission to access it. Specify a valid path.

Yet it still gives me that error!

The specified UNC path does not contain a valid boot image file or you do not have permission to access it. Specify a valid path.

Welp – Time to troubleshoot.

typey, typey, type

First thing I checked is permissions. I verified that the site server computer account had full permissions for NTFS on that drive and within sharing for that particular share. Also, I verified that the service account had full permissions to NTFS and sharing, just in case. I even checked the permissions on the boot.wim file thinking maybe they didn’t inherit properly. None of that seemed to matter.

Next thing I checked is if the boot.wim is a valid boot image. I started up psexec in the context of system so I could run dism to verify that I could mount the boot.wim with:

psexec -i -s cmd

and then:

dism /mount-image /imagefile:”c:\bootimagex64\media\sources\boot.wim” /index:1 /mountdir:”C:\bootimagex64mount”

Then I go browse over to c:\bootimagex64mount and I can see the boot image successfully mounted so I know I can unmount it with:

dism /unmount-image /mountdir:”c:\bootimagex64mount” /discard

I was still unable to add this boot image to ConfigMgr.

So, I did what any self-respecting sysadmin would do and I went grovelling to my community for assistance. I tried the winadmins slack first, but the ideas presented didn’t get me anywhere.

[If you aren’t in the winadmins slack yet, then head on over and join us]

  • I tried using an alternate boot.wim, like the ones found at <ConfigMgrInstallDirectory>\OSD\boot\x64, but was met with the same error message as before.
  • Also, I really didn’t want to rollback the ADK, even just for testing purposes. I was willing to try it, as a last recourse. Since the support matrix shows it supported, but I’m stubborn.
Windows 10 ADK & ConfigMgr Support Matrix

https://docs.microsoft.com/en-us/sccm/core/plan-design/configs/support-for-windows-10#windows-10-adk

Next I went to reddit and posted on /r/sccm to see if I could get any help there.

reddit post

https://www.reddit.com/r/SCCM/comments/c1qdiq/issues_importing_boot_image/

I was fully prepared for Jason Sandys to jump in and comment as he seems to be on the most popular Google results for this error message and he’s present on technet and reddit comments that I was looking at during my research, but I think I got an even better response…

I love you /u/vsoro00

https://www.reddit.com/r/SCCM/comments/c1qdiq/issues_importing_boot_image/erf7apl

I blame Jeffrey Snover for making me not want to click buttons, but really … I’m not a smart man. I cannot believe I never thought to browse to the damn wim file.

Windows 10 ADK & ConfigMgr Support Matrix

https://twitter.com/jsnover/status/386104326000627713

I came into the office today and decided to listen to /u/vsoro00 and click that browse button:

Windows 10 ADK & ConfigMgr Support Matrixand wouldn’t you know it … it worked!

I still don’t understand how this is functionally different from my typing it … but hey!

SUCCESS!

Woot! Now let’s make sure it will fully import…

The Error Message That Wasted Part Of My Day - or - I Am Not A Smart Man...

There we have it folks … a new boot image added successfully!

I want to say a heartfelt thank you to /u/vsoro00, who I assume is Vladimir Sorokin over on the ConfigMgr team at Microsoft, for taking time to answer my post in reddit with exactly what I needed to hear. Also, I don’t understand the technical limitations they are working with or what he means about how expensive the process can be to validate everything I type in, but if this is truly an issue for others than I look forward to them removing the typing functionality altogether! I love this community!

Chris Thomas
@AutomateMyStuff

Post OSD Scheduled Task

, ,

Post OSD Scheduled Task


Every organization handles OSD differently. Currently at our organization we do have some apps that have been ‘baked into the task sequence’  as an ‘Install Application’ step for a very long time and are needed on every single imaged machine. These work perfectly, install consistently and generally there are no ‘exceptions’ to a PC having the software.

This isn’t the case with all of our widely distributed applications, and rather than build the logic into the task sequence we let the collections do the work after imaging. After a period of time when the appropriate collections are updated on their various schedules these new machines happily receive their software and baselines and go on their merry way as we know all healthy SCCM clients do! In the day-to-day SCCM world this works perfectly fine. Machines are added to collections through whatever method your organization uses, whether it be Direct Membership, AD Group/OU Queries, name based queries, hardware inventory based queries and there is a general understanding that machines will pop into the collection and receive their Applications/Updates/CIs in good time.

When our techs image a machine it can be helpful for it to temporarily have some expedited policy refresh rates for a period of time to speed up those after-the-fact deployments. We had tried a few collection queries to catch these ‘new machines’ so that we could deploy some aggressive Client Settings to them, but generally there is never a perfect query. Usually you catch not just new machines but instead those risen from the dead pit of being stale, or they were rejoined to the domain, maybe the client was reinstalled or some form of in place upgrade happened.  As an alternative to the collection query I wrote up a Powershell script.


What Does It Do?


It creates a scheduled task! 

The script can be ran from a ‘Run Command Line’ or ‘Run Powershell Script’ step during OSD (Typically near/at the end) with various parameter options. You’ll have to toss it into a package to serve up to the task sequence of course. It will create a scheduled task that runs specified SCCM Client Policy requests at whatever interval you want for as long as you want. Also, the task deletes itself shortly after the duration has passed. I didn’t quite include all the of schedule types because there is a very long list. But most of the key ones are there and any others can be easily added. 


How Do I Use It?


New-ClientActionScheduledTask.ps1 -Schedule MachinePol -Interval 5

This will create a schedule task that runs every 5 minutes for 24 hours. I did say aggressive at least once up there right? The task will receive a generated name based on the requested schedules. The above would produce a task named –
SCCM Action Scheduler – [MachinePol]
Which calls a file (Start-CMClientAction.ps1)  that is generated and stored in c:\windows\temp

Both the task name and the file name can be specified as parameters to the script aptly named… -FileName and -TaskName


New-ClientActionScheduledTask.ps1 -Schedule AppEval, HardwareInv, UpdateEval, UpdateScan -Interval 30 -Duration 12
Task Sequence Example

Similar results with this execution of the line above. A task is created, but with it running every 30 minutes for a 12 hour period. The task will appear in task scheduler with a title –
SCCM Action Scheduler – [AppEval,HardwareInv,UpdateEval,UpdateScan]
Which is based on the actions provided.


Where Do I Git It?


GitHub! I intend to continue adding to this GitHub repository.

https://github.com/CodyMathis123/CM-Ramblings/blob/master/New-ClientActionScheduledTask.ps1


Neat Stuff:


I’ve also used a couple of bits of code you might find interesting to create the scheduled task. Maybe you’ve seen it, maybe you haven’t.


${Function:Invoke-CCMClientAction}

This will write-out the contents of many functions (note: function, not cmdlet). I am leveraging this to generate a .ps1 file that can be easily invoked by the task sequence.

Neat right? I wrote that function though… but what is more interesting is you can do this with some built in functions! Try ${function:Clear-Host} or ${function:Get-Verb} and you can see some of the magic behind at least some commands you’ve used. Many are compiled cmdlets and are simply not expandable like this but can be dug into in other ways.


$TaskDefinition.Settings.DeleteExpiredTaskAfter = "PT0S"

https://docs.microsoft.com/en-us/windows/desktop/taskschd/tasksettings-deleteexpiredtaskafter

While this can be a bit odd to work with, the above piece of code allows our scheduled task to ‘delete itself’ after it expires. Specifically… zero seconds after it expires. T is just a delimiter between date and time (Eg. days vs hours/minutes/seconds). You will need to specify an ‘EndBoundary’ for this to function, which is what our ‘Duration’ is in this.


function New-ScheduledTaskTimeString {
    param(
        [Parameter(Mandatory = $false)]
        [int]$Hours = 0,
        [Parameter(Mandatory = $false)]
        [int]$Minutes = 0
    )
    $TimeSpan = New-TimeSpan -Hours $Hours -Minutes $Minutes
    $TimeSpanDays = $TimeSpan | Select-Object -ExpandProperty Days
    $TimeSpanHours = $TimeSpan | Select-Object -ExpandProperty Hours
    $TimeSpanMinutes = $TimeSpan | Select-Object -ExpandProperty Minutes

    if ($TimeSpanDays -gt 0) {
        $OutputDays = [string]::Format("{0}D", $TimeSpanDays)
    }

    if ($TimeSpanHours -gt 0 -or $TimeSpanMinutes -gt 0) {
        $Delimiter = 'T'
        if ($TimeSpanHours -gt 0) {
            $OutputHours = [string]::Format("{0}H", $TimeSpanHours)
        }

        if ($TimeSpanMinutes -gt 0) {
            $OutputMinutes = [string]::Format("{0}M", $TimeSpanMinutes)
        }
    }

    [string]::Format("P{0}{1}{2}{3}", $OutputDays, $Delimiter, $OutputHours, $OutputMinutes)

}

You give me hours and minutes, I give you a PnDTnHnMnS string to use for a scheduled task.
Just a quick function I wrote for the purposes of dumping out usable strings for time intervals that task scheduler understands.


I opted to not use the *-ScheduledTask* commands available post-Win 7. You could ‘simplify’ the code a bit for the task creation if you don’t mind being incompatible with Windows 7 by using these.

Is this the right way to do it? Who knows! I’m sure with some very careful inspection and categorization of our collections and their refresh schedules we could help the situation in other ways. Still a neat bit of code.

@CodyMathis123

https://sccmf12twice.com/author/cmathis/