Archive | SCCM

Using PowerShell to unpin the AppStore in Windows 10 – Workaround

I can’t find a way to unpin the AppStore in Windows 10. So I wen’t about it another way.
I reset the taskbar to have nothing and then I added everything back that I wanted.
I am using this in my OSD/RunOnce PowerShell script to customize the user’s desktop.

First of all I am using this function to manipulate the registry:

Function ChangeRegistry{
PARAM(
$ErrorActionPreference = "SilentlyContinue",
[Parameter(Mandatory=$true)]$registryPath,
[Parameter(Mandatory=$true)]$Name,
[Parameter(Mandatory=$true)]$Value ,
[Parameter(Mandatory=$true)]$PropertyType,
$Comment
)
Try {
 $RESULT=Get-ItemProperty -Path $registryPath -Name $Name | Out-Null
 New-ItemProperty -Path $registryPath -Name $Name -Value $Value -PropertyType $PropertyType -Force | Out-Null
}
Catch [System.Management.Automation.PSArgumentException] {
  New-ItemProperty -Path $registryPath -Name $Name -Value $Value -PropertyType $PropertyType -Force | Out-Null 
}
Catch [System.Management.Automation.ItemNotFoundException] {
  New-Item -Path $registryPath -Force | Out-Null
  New-ItemProperty -Path $registryPath -Name $Name -Value $Value -PropertyType $PropertyType -Force | Out-Null 
}
Finally { 
$ErrorActionPreference = "Continue" 
Write-host "$($Comment)$($Name): $Value"
}
}

Next I reset the Taskbar:

Write-Host "Setting up Start Menu" -ForegroundColor Green
ChangeRegistry -registryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband" -Name "Favorites" -PropertyType "Binary" -Value ([byte[]](0xFF))
ChangeRegistry -registryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband" -Name "FavoritesResolve" -PropertyType "Binary" -Value ([byte[]](0xFF))
ChangeRegistry -registryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband" -Name "FavoritesChanges" -PropertyType "DWORD" -Value 0
ChangeRegistry -registryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband" -Name "FavoritesVersion" -PropertyType "DWORD" -Value 1
Stop-Process -Name explorer -ErrorAction SilentlyContinue

Finally I use the InvokeVerb method to put back what I want:

$ShellApplication = New-Object -ComObject Shell.Application
$result=$ShellApplication.Namespace("C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office").ParseName("Microsoft Outlook 2010.lnk").InvokeVerb("taskbarpin")

Re-imaging a machine, with SCCM 2012 fails with error 0x80070570

I have been working on building a new Windows 10 image. I was testing on a laptop and all of the sudden the OSD Task Sequence started failing, before anything even started!
I had only made a minor change to the TaskSequence, so I was pulling my hair out.

Error 0x80070570. 
Logs shows : threadtoresolveandexecutetasksequence failed 0x80070570.

If you are impatient like me, then you you power off the machine (press and hold the power button), and start over.
Well, that was the issue. Drive was marked as dirty (so many power offs throughout the day!) and a check disk needed to be run.

Hope that helps someone.

Problems with TweetDeck and Enterprise Deployment (SCCM)

Been working with @xrobx99 on this one. We had a request for TweetDeck to be installed on a couple of user’s machines. We feared that word would get out and everyone would have to have it. So we have been looking into deploying TweeDeck silently through SCCM. Using my SCCM PowerShell install script (which is basically just a wrapper for the msi commands) we have observerd the following issues below:

When run silently with the command:  msiexec /i TweetDeck.msi /q /norestart /l c:\Temp\TweetDeck.log

  • Short-cuts don’t get created
  • TweetDeck does not show up in Add Remove programs

Other Non-enterprise ready issues that we have observed:

  • No way to know the current version number without installing first (shouldn’t it be in the MSI properties?)
  • Web site does not show the current version number
  • Is there a way to NOT check/prompt for update on close? This is annoying for non-administrators (they get a UAC prompt)
  • Twitter’s registry entry in HKCU\Software is not with a capitol “T” (I know, weak, but that kind of stuff drives me crazy)

It is entirely possible that I am doing something wrong, but those are my findings.

UPDATE I realized that I can use the ALLUSERS=1 parameter and the program will be installed for all users, then the Icons and Add remove programs will be correct. Maybe the packagers need to include ALLUSERS=1 in their packaging software? Updated install string:

msiexec /i TweetDeck.msi ALLUSERS=1 /q /norestart /l c:\Temp\TweetDeck.log

5 PowerShell functions to create a SCCM “trickle install” – i.e. X at a time.

If you look at this post, I describe a my idea of a SCCM trickle install – that is X number of machines at a time. Rather that have the install hit the whole collection at once, I wanted to hit just 20 a night. That way if there is an error, we can put the breaks on the deployment. We create dynamic collections that use a “NOT IN” SQL statement – this results in all the machines that are in the collection need the specific software. This script copies X at a time from that collection to new collection.

In the previous post, I run a VBScript that loops through the first 10 (or X) number of machines in the collection and add them to a new collection that contains the assigned advertisement. The next night, the script runs again, and the next 10 (or X) are copied (since the source collection is dynamic, the machines from the night before are removed).

I wanted to do the same thing, but I wanted to use PowerShell. First up, a function to find a Collection’s Id.

FUNCTION JBM-SCCM-GetCollection {
	Param([parameter(Mandatory = $true)]$CollectionName,
	$SiteName="JBM",
	$SCCMServer="sccmserver.domain.com")
	$SCCMNameSpace="root\sms\site_$SiteName"
	$QUERY="Select CollectionID from SMS_Collection WHERE Name = '$CollectionName'"
	Return $(Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query $QUERY)
}

Next a function to find all the machines in a collection:

FUNCTION JBM-SCCM-GetCollectionMembers{
Param([parameter(Mandatory = $true)]$CollectionID,
	$SiteName="JBM",
	$SCCMServer="sccmserver.domain.com")
	$SCCMNameSpace="root\sms\site_$SiteName"
	$QUERY="SELECT Name FROM SMS_FullCollectionMembership WHERE CollectionID = '$CollectionID'"
	Return $(Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query $QUERY)
}

Next a function to remove all machines in a collection (the ones that are directly added)

FUNCTION JBM-SCCM-DeleteAllCollectionMembers{
Param([parameter(Mandatory = $true)]$CollectionID,
	$SiteName="JBM",
	$SCCMServer="sccmserver.domain.com")
	$SCCMNameSpace="root\sms\site_$SiteName"
    $Collection=[WMI]"\\$($SCCMServer)\$($SCCMNameSpace):SMS_Collection.CollectionID='$CollectionID'"
	ForEach ($Rule in  $Collection.CollectionRules ){
    $Collection.DeleteMembershipRule($Rule)
    }
}

Next, a function to add a machine to a Collection:

FUNCTION JBM-SCCM-AddCollectionMember{
Param([parameter(Mandatory = $true)]$CollectionID,
	$SiteName="JBM",
	$SCCMServer="sccmserver.domain.com",
    [parameter(Mandatory = $true)]$ComputerToAdd)
	$SCCMNameSpace="root\sms\site_$SiteName"

    $computer = gwmi -computer $SCCMServer -namespace $SCCMNameSpace -Query "select * from SMS_R_System where NetBiosName='$ComputerToAdd'"
    $Collection=[WMI]"\\$($SCCMServer)\$($SCCMNameSpace):SMS_Collection.CollectionID='$CollectionID'"
    $ruleClass = [wmiclass]"\\$($SCCMServer)\$($SCCMNameSpace):SMS_CollectionRuleDirect"
    $newRule = $ruleClass.CreateInstance() 
    $newRule.RuleName = $ComputerToAdd 
    $newRule.ResourceClassName = "SMS_R_System" 
    $newRule.ResourceID = $computer.ResourceID 
    $null = $Collection.AddMembershipRule($newRule) 
}

Finally, a function to copy machines from one collection to another, using the functions above:

FUNCTION JBM-SCCM-CopyCollectionMembers {
Param([parameter(Mandatory = $true)]$SourceCollectionName,
    [parameter(Mandatory = $true)]$DestinationCollectionName,
    [parameter(Mandatory = $true)]$NumberToCopy)

    $SrcCollID=JBM-SCCM-GetCollection($SourceCollectionName)
    $DstCollID=JBM-SCCM-GetCollection($DestinationCollectionName)
    $SrcCollMembers=JBM-SCCM-GetCollectionMembers($SrcCollID.CollectionID)
    JBM-SCCM-DeleteAllCollectionMembers($DstCollID.CollectionID)
    foreach ($Computer in $($SrcCollMembers | select -first $NumberToCopy)){
    JBM-SCCM-AddCollectionMember -CollectionID $DstCollID.CollectionID -ComputerToAdd $Computer.Name
    }

}

The result – a trickle install.

PowerShell script to create a SCCM Package,Program and Queries

I wanted to automate the process of creating a new package. The following code will look at an XML file for values (same xml file I am using here) and create a package based on the values. A lot of SCCM PowerShell was gathered from here. Here is the example of the source XML file:

<Install>
<Params>
<PkgName Value="Firefox" />
<PkgManufacturer Value="Mozilla" />
<PkgVersion Value="12.0" />
<PkgSourcePath Value="\\domain.local\DFSRoot\Path\Mozilla\Firefox-12.0" />
<PkgcontainerNodeID Value="17" />
<CurrentVersionQueryName Value="Software-MozillaFirefox-12.0" />
<OtherThanQueryName Value="Software-MozillaFirefox-OtherThan-12.0" />
<QuerycontainerNodeID Value="4" />
</Params>
</Install>

And here is the script that creates the package, program, distribution point,and 2 queries (A query to show where version is installed, and a second to show where it is not installed (NOT IN).)

function JBMMURPHY-SCCM-CreatePackageAndQueries{
PARAM(
    [Parameter(Mandatory=$true)]
    [ValidateScript({Test-Path $_})]
    $XMLFilePath)
[ xml ]$s = Get-Content $XMLFilePath

$NAMESPACE="root\SMS\Site_LAB"
$PkgName=$s.Install.SCCMParams.PkgName.Value
$PkgManufacturer=$s.Install.SCCMParams.PkgManufacturer.Value
$PkgVersion=$s.Install.SCCMParams.PkgVersion.Value
$PkgSourcePath=$s.Install.SCCMParams.PkgSourcePath.Value
$PkgcontainerNodeID=$s.Install.SCCMParams.PkgcontainerNodeID.Value
$OtherThanQueryName=$s.Install.SCCMParams.OtherThanQueryName.Value
$CurrentVersionQueryName=$s.Install.SCCMParams.CurrentVersionQueryName.Value
$QuerycontainerNodeID=$s.Install.SCCMParams.QuerycontainerNodeID.Value
$PkgProgramFlags=135308289
$PkgCommandLine = "powershell .\SVCInstall.ps1"

## create package and move into appropriate folder
$PackageProperties = @{
Name = $PkgName;
Manufacturer = $PkgManufacturer;
Version = $PkgVersion;
Language = "English (United States)";
PackageType = 0;
PkgSourceFlag = 2;
PkgSourcePath = $PkgSourcePath
Priority = 2
}
$newPackage = Set-WmiInstance -class SMS_Package -arguments $PackageProperties -namespace $NAMESPACE
$newPackage | Format-List | Out-Null
write-host "pkgid=$($newPackage.PackageID)"

## Move Package
$MovePackage = @{
InstanceKey = $newPackage.PackageID;
ObjectType = 2;
ContainerNodeID = $PkgcontainerNodeID
}
Set-WmiInstance -Class SMS_ObjectContainerItem -arguments $MovePackage -namespace $NAMESPACE

## create new program = Per-system unattended

$NewProgram = @{
PackageID = $newPackage.PackageID;
ProgramFlags = $PkgProgramFlags;
ProgramName = "Per-system unattended";
CommandLine = $PkgCommandLine
}
Set-WmiInstance -class SMS_Program -arguments $NewProgram -namespace $NAMESPACE

## Add Distribution point to package

$NewDistPointForPackage = @{
PackageID = $newPackage.PackageID;
ServerNALPath = '["Display=\\SERVENAME\"]MSWNET:["SMS_SITE=LAB"]\\SERVERNAME\';
SiteCode = "LAB";
SiteName = "LAB";
SourceSite = "LAB";
ResourceType = "Windows NT Server"
}
Set-WmiInstance -class SMS_DistributionPoint -arguments $NewDistPointForPackage -namespace $NAMESPACE


## Creating Queries

## Current Verson Query
$CurrentVersionQuery="select SMS_R_System.Name, SMS_R_System.LastLogonUserName, SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName, SMS_G_System_ADD_REMOVE_PROGRAMS.Version 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_R_System.Client = 1 and SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName like `'$($PkgName)%`' and SMS_G_System_ADD_REMOVE_PROGRAMS.Version = `'$($PkgVersion)`' order by SMS_R_System.Name";
$CurrentVersionQueryHash = @{
Name = $CurrentVersionQueryName;
Expression = $CurrentVersionQuery;
TargetClassName = "SMS_R_System"
}
$newCurrentVersionQuery = Set-WmiInstance -class SMS_Query -arguments $CurrentVersionQueryHash -namespace $NAMESPACE
$newCurrentVersionQuery  | Format-List | Out-Null

[email protected]{
InstanceKey = $newCurrentVersionQuery.QueryID;
ObjectType = 7;
ContainerNodeID = $QuerycontainerNodeID
}
Set-WmiInstance -Class SMS_ObjectContainerItem -arguments $MoveCurrentVersionQuery -namespace $NAMESPACE


## Other Than Query
$OtherThanQuery="select SMS_R_System.Name, SMS_R_System.LastLogonUserName, SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName, SMS_G_System_ADD_REMOVE_PROGRAMS.Version 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_R_System.Client = 1 and SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName like `'$($PkgName)%`' and SMS_R_System.Name not in (select SMS_R_System.Name 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_R_System.Client = 1 and SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName like `'$($PkgName)%`' and SMS_G_System_ADD_REMOVE_PROGRAMS.Version = `'$($PkgVersion)`') order by SMS_R_System.Name"
$OtherThanQueryHash [email protected]{
Name = $OtherThanQueryName;
Expression = $OtherThanQuery;
TargetClassName = "SMS_R_System"
}
$newOtherThanQuery = Set-WmiInstance -class SMS_Query -arguments $OtherThanQueryHash -namespace $NAMESPACE
$newOtherThanQuery  | Format-List | Out-Null

[email protected]{
InstanceKey = $newOtherThanQuery.QueryID;
ObjectType = 7;
ContainerNodeID = $QuerycontainerNodeID
}
Set-WmiInstance -Class SMS_ObjectContainerItem -arguments $MoveOtherThanQuery -namespace $NAMESPACE

# To Find Node: gwmi -Namespace $NAMESPACE -query "Select * from SMS_ObjectContainerNode WHERE Name = 'ContainerName'"
# Example run: JBMURPHY-SCCM-CreatePackage -XMLFilePath \\domain.local\DFSRoot\Path\Install.xml
#
}

PowerShell, Active Setup and running a SCCM package “before log on”

I have been struggling with the following idea for a while: How to run a package before before a person logs on using SCCM. There is a setting in SCCM that runs when no one is logged on, but if a person reboots and logs on before SCCM fires, the package will never run. Basically I wanted the ability to make SCCM work like Software Deployment in AD (AD prevents you from logging on until software is completely installed).

The missing piece, for me, was “Active Setup”. Active Setup is pretty well documented here. Combining Active Setup with PowerShell and SCCM, I believe I can run packages before people log on (or at least before they launch any programs).

Here are my steps

  • Step 1 : I need to create an Active Setup registry entry on everyone’s machine that will run a PowerShell script
    • I created this PowerShell script to create the Active Setup registry entries. This will put a StubPath that launches the PowerShell script.
  • Step 2 : Pop up an info message telling the user we are doing some work before the finish logging in.
  • Step 3 : Launch the SCCM Advertised program that you want. Since Active Setup is running as the user, you have to use SCCM to run anything that needs “administrative privileges”. The following code is used inside a PowerShell script to launch an advertisement on the local machine (you need to know the ProgramID and the PackageID):
Function JBMURPHY-SCCM-UIExecuteProgram {
 Param([parameter(Mandatory = $true)]$ProgramID,
       [parameter(Mandatory = $true)]$PackageID)
 $UIResource = New-Object -ComObject UIResource.UIResourceMgr
 $UIResource.ExecuteProgram($ProgramID, $PackageID,$true)
}

Kinda complicated, but I think it will work. Have you used these methods?

Dotted (period) NetBIOS Domain Name issues

I inherited a Dotted Netbios Domain Name. Technically it is allowed, but it is not recommended. With every new version of software, I cringe in fear that it will come back to bite us again. For example:

  1. Moving from Exchange 2003 to 2010 was a problem for a while, but it seemed to been resolved and we migrated from 2003 to 2010 with out issue.
  2. When I tried to upgrade SCCM 2007 to SP 2, it failed as I describe in this thread. I had to install fresh from a slipstreamed  installer.
  3. Most recently, when I try to install CRM 2011 in our dotted domain, it failed. In my reading yesterday, I realized Rollup 4 has the following: “When the NetBIOS name of the domain contains a period (.), the installation of Microsoft Dynamics CRM 2011 fails.”
    • I still can’t add a new organization, but I was able to restore an organization from a dev server in a non-dotted netbios domain.
  4. I will add more as I find them.
The problem seems to be that with each new installer, the developers assume that if there is a period in the domain name, then the user has supplied a FQDN by accident.

PowerShell Query to find a users computer name in SCCM

We rely on Remote Assistance. Usually, I just type “msra /offerra” in to my PowerShell session and lookup a the user’s computer name in the SCCM report named “Computers for a specific user name”. I wanted to make that process quicker. I wrote the following script to query SCCM for the “list of computer’s who’s last logged on user” is the person I am looking for.

FUNCTION JBMURPHY-SCCM-GetComputerByLastLoggedOnUser {
Param([parameter(Mandatory = $true)]$SamAccountName,
	$SiteName="JBM",
	$SCCMServer="SCCMServer.domain.local")
	$SCCMNameSpace="root\sms\site_$SiteName"
	Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select Name from sms_r_system where LastLogonUserName='$SamAccountName'" | select Name
}

Let me know if this is useful to you!

PowerShell scripts to create a WinPE 4.0 wim/ISO

I have been  a WinPE hacker since it was only available to SA subscribers. With Vista it was free to the world, and I started moving all my setup processes to it. I have always used the dos batch scripts found in this forum to create a new WinPE ISO. Since WinPE 4.0 is coming out with Windows 8 (if not before (I don’t know timelines)), I wanted to modify the dos batch files I rely on to work with WinPE 4.0. Since WinPE 4.0 has PowerShell in it, I wanted to migrate those dos batch files to PowerShell functions. Working from the dos batch files linked above and this post I created the functions below. They have numbers in their names because they are the steps to follow when creating a new ISO.

Function JBMURPHY-WinPE-1MakePEDirectory{
	Param($OSArchitecture="x86")

 remove-item -force "c:\PE\winpe_$OSArchitecture"
 New-Item c:\PE\winpe_$OSArchitecture\ISO\sources -type directory -force
 New-Item c:\PE\winpe_$OSArchitecture\mount -type directory -force
 copy-item "C:\Program Files\Windows Kits\8.0\Assessment and Deployment Kit\Windows Preinstallation Environment\$OSArchitecture\winpe.wim" "c:\PE\winpe_$OSArchitecture\ISO\sources\boot.wim"
 copy-item "C:\Program Files\Windows Kits\8.0\Assessment and Deployment Kit\Windows Preinstallation Environment\$OSArchitecture\Media\*" "c:\PE\winpe_$OSArchitecture\ISO\" -recurse
 copy-item "C:\Program Files\Windows Kits\8.0\Assessment and Deployment Kit\Deployment and Imaging Tools\$OSArchitecture\Oscdimg\etfsboot.com" "c:\PE\winpe_$OSArchitecture\"

}

Function JBMURPHY-WinPE-2Mount{
	Param($OSArchitecture="x86",$WimFile="c:\PE\winpe_$OSArchitecture\ISO\sources\boot.wim")
	DISM.exe /Mount-Wim /WimFile:$WimFile /index:1 /MountDir:C:\PE\winpe_$OSArchitecture\mount
}

Function JBMURPHY-WinPE-3.0AddPAckages{
	Param($OSArchitecture="x86",$WimFile="c:\PE\winpe_$OSArchitecture\ISO\sources\boot.wim")
	$OCsPATH="C:\Program Files\Windows Kits\8.0\Assessment and Deployment Kit\Windows Preinstallation Environment\$OSArchitecture\WinPE_OCs"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\WinPE-Scripting.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\en-us\WinPE-Scripting_en-us.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\WinPE-WMI.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\en-us\WinPE-WMI_en-us.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\WinPE-MDAC.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\en-us\WinPE-MDAC_en-us.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\WinPE-HTA.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\en-us\WinPE-HTA_en-us.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\WinPE-NetFx4.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\en-us\WinPE-NetFx4_en-us.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\WinPE-PowerShell3.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\en-us\WinPE-PowerShell3_en-us.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\WinPE-DismCmdlets.cab"
	dism /image:C:\PE\winpe_$OSArchitecture\mount /add-package /packagepath:"$OCsPATH\en-us\WinPE-DismCmdlets_en-us.cab"
}

Function JBMURPHY-WinPE-5UnMount-NoCommit{
	Param($OSArchitecture="x86",$WimFile="c:\PE\winpe_$OSArchitecture\ISO\sources\boot.wim")
	DISM.exe /unmount-Wim /MountDir:C:\PE\winpe_$OSArchitecture\mount /discard
}
Function JBMURPHY-WinPE-5UnMount{
	Param($OSArchitecture="x86",$WimFile="c:\PE\winpe_$OSArchitecture\ISO\sources\boot.wim")
	DISM.exe /unmount-Wim /MountDir:C:\PE\winpe_$OSArchitecture\mount /Commit
}

Function JBMURPHY-WinPE-6MakeISO {
	Param($OSArchitecture="x86",$WimFile="c:\PE\winpe_$OSArchitecture\ISO\sources\boot.wim")
	$command="C:\Program Files\Windows Kits\8.0\Assessment and Deployment Kit\Deployment and Imaging Tools\$OSArchitecture\Oscdimg\oscdimg.exe"
	&$command  -n -bc:\PE\winpe_$OSArchitecture\etfsboot.com c:\PE\winpe_$OSArchitecture\ISO c:\PE\winpe_$OSArchitecture\winpe_$OSArchitecture.iso
}

I have not tried this on x64, but I think you would need to pass -OSArchitecture amd64 to each function . Is it me or does Microsoft flip-flop between x64 and amd64 naming conventions?