Category: Snowland.se

Default Powershell Execution Policy

You can use a GPO to set the ExecutionPolicy to a static value on all machines.

But what if you want to default it to something and then let the users have the ability to change it?

Group Policy Preferences is the easy answer.

Create a GPO targeting your machines and then create a entry under Computer Configuration -> Preferences -> Windows Settings -> Registry that looks like this:
130917-execpolicy-1

130917-execpolicy-2

The paths are:
Key: SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell
Value Name: ExecutionPolicy
ValueData: RemoteSigned

With this setup a machine that doesn’t have any specific exec policy (then the reg key doesn’t exist) setup will get RemoteSigned.
(Another way is to do this with a startup script for the computer)

Win7 Themes and Screensaver

If you want to enforce users to use a specific screensaver you can do most of it via standard group policies. But if you run Windows 7 and a user changes the current theme… the screensaver will be blank until the next group policy refresh.
This is due to that the default .theme-files have no screensaver defined.

With Group Policy Preferences you can change this…

First we need to change the current ACL on the themes directories since SYSTEM cant write there.

Edit or create a Group Policy.
Browse to Computer Configuration – Windows Settings – Security Settings – File System
Right Click and select Add File… then write %SystemRoot%\Resources\Themes in the Folder-box.
Set the security rights as you want them, but remember to give SYSTEM the rights to Modify.
In the dialog “Add Object” that pops up when you press OK, select Replace existing permissions on all suboflders and files with inheritable permissions, this option is not selected as a default.
Repeat that for %SystemRoot%\Resources\Ease of Access Themes directory.

Then browse to Computer Configuration – Preferences – Windows Settings – Ini Files
Right Click and select New – Ini File
Give the following options:

(I would recommend that you set a item level targeting to check that the file exist)

Now to the boring part, repeat that for all Theme-files in the directories %SystemRoot%\Resources\Themes and %SystemRoot%\Resources\Ease of Access Themes

If there is something else you want to change you can find loads of options for themes in this reference http://msdn.microsoft.com/en-us/library/bb773190%28v=vs.85%29.aspx

No more secrets…???

After almost 10 years (3 weeks short) at Atea Sweden I’m now leaving the company for an employment on the customer side.
Since I’m not working at a consultant company that sells the kind of solutions I’m blogging about… I have no “restrictions” on what I can blog about.

Hope that I can share more of my scripts, findings and solutions instead of keeping them as a “company secret”.

No more secrets! 🙂

On the one hand information wants to be expensive, because it’s so valuable. The right information in the right place just changes your life. On the other hand, information wants to be free, because the cost of getting it out is getting lower and lower all the time. So you have these two fighting against each other.

Thoughtful quote by Stewart Brand at the first Hackers’ Conference back in 1984

Written by Comments Off on No more secrets…??? Posted in Snowland.se

SCCM PoSH

Changelog

  • 2013-05-09 (Ricardo Cheing)
    Bugfix: Add-SCCMDirUserCollectionRule (Corrected Get-User to Get-SCCMUser)
  • 2010-10-29 (Rikard Ronnkvist)
    New functions: Update-SCCMDriverPkgSourcePath, Update-SCCMPackageSourcePath, Update-SCCMDriverSourcePath
  • 2010-10-06 (Stefan Ringler)
    New and updated functions from http://www.stefanringler.com/?p=150 (New-SCCMPackage, New-SCCMAdvertisement, New-SCCMProgram, Add-SCCMDistributionPoint)
  • 2010-09-13 (Rikard Ronnkvist)
    Bugfix: Get-SCCMCollectionMembers (Thanks to Milos)
    Bugfix: Add-SCCMCollectionRule (Thanks to Luigi)
  • 2010-03-26 (Rikard Ronnkvist)
    Separate page on snowland.se
    New function: New-SCCMPackage
  • 2010-03-23 (Rikard Ronnkvist)
    Fixed some small bugs
    Added limitToCollectionId in Add-SCCMCollectionRule
  • 2010-03-10 (Rikard Ronnkvist)
    Major makeover
    First snowland.se release
  • 2009-04-07 (Michael Niehaus)
    Original code posted at http://blogs.technet.com/mniehaus/

Usage:

  • Save the file as SCCM-Commands.psm1
  • PS:>Import-Module SCCM-Commands
  • PS:>Get-SCCMCommands

SCCM-Commands.psm1

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#                                                                                                                            Rikard Ronnkvist / snowland.se
#  Usage:
#   Save the file as SCCM-Commands.psm1
#   PS:>Import-Module SCCM-Commands
#   PS:>Get-SCCMCommands
#
#  2009-04-07   Michael Niehaus     Original code posted at http://blogs.technet.com/mniehaus/
#  2010-03-10   Rikard Ronnkvist    Major makeover and first snowland.se release
#  2010-03-23   Rikard Ronnkvist    Fixed some small bugs and added limitToCollectionId in Add-SCCMCollectionRule
#  2010-03-26   Rikard Ronnkvist    New function: New-SCCMPackage
#  2010-09-13   Rikard Ronnkvist    Bugfixes to Add-SCCMCollectionRule and Get-SCCMCollectionMembers (Thanks to comments on snowland.se from Milos and Luigi)
#  2010-10-06   Stefan Ringler      New and updated functions from http://www.stefanringler.com/?p=150 (New-SCCMPackage, New-SCCMAdvertisement, New-SCCMProgram, Add-SCCMDistributionPoint)
#  2010-10-29   Rikard Ronnkvist    New functions: Update-SCCMDriverPkgSourcePath, Update-SCCMPackageSourcePath, Update-SCCMDriverSourcePath
#  2013-05-09   Ricardo Cheing      Bugfix: Add-SCCMDirUserCollectionRule (Corrected Get-User to Get-SCCMUser)
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Get-SCCMCommands {
	# List all SCCM-commands
	[CmdletBinding()]
	PARAM ()
	PROCESS {
		return Get-Command -Name *-SCCM* -CommandType Function  | Sort-Object Name | Format-Table Name, Module
	}
}

Function Connect-SCCMServer {
	# Connect to one SCCM server
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$false,HelpMessage="SCCM Server Name or FQDN",ValueFromPipeline=$true)][Alias("ServerName","FQDN","ComputerName")][String] $HostName = (Get-Content env:computername),
		[Parameter(Mandatory=$false,HelpMessage="Optional SCCM Site Code",ValueFromPipelineByPropertyName=$true )][String] $siteCode = $null,
		[Parameter(Mandatory=$false,HelpMessage="Credentials to use" )][System.Management.Automation.PSCredential] $credential = $null
	)

	PROCESS {
		# Get the pointer to the provider for the site code
		if ($siteCode -eq $null -or $siteCode -eq "") {
			Write-Verbose "Getting provider location for default site on server $HostName"
			if ($credential -eq $null) {
				$sccmProviderLocation = Get-WmiObject -query "select * from SMS_ProviderLocation where ProviderForLocalSite = true" -Namespace "root\sms" -computername $HostName -errorAction Stop
			} else {
				$sccmProviderLocation = Get-WmiObject -query "select * from SMS_ProviderLocation where ProviderForLocalSite = true" -Namespace "root\sms" -computername $HostName -credential $credential -errorAction Stop
			}
		} else {
			Write-Verbose "Getting provider location for site $siteCode on server $HostName"
			if ($credential -eq $null) {
				$sccmProviderLocation = Get-WmiObject -query "SELECT * FROM SMS_ProviderLocation where SiteCode = '$siteCode'" -Namespace "root\sms" -computername $HostName -errorAction Stop
			} else {
				$sccmProviderLocation = Get-WmiObject -query "SELECT * FROM SMS_ProviderLocation where SiteCode = '$siteCode'" -Namespace "root\sms" -computername $HostName -credential $credential -errorAction Stop
			}
		}

		# Split up the namespace path
		$parts = $sccmProviderLocation.NamespacePath -split "\\", 4
		Write-Verbose "Provider is located on $($sccmProviderLocation.Machine) in namespace $($parts[3])"

		# Create a new object with information
		$retObj = New-Object -TypeName System.Object
		$retObj | add-Member -memberType NoteProperty -name Machine -Value $HostName
		$retObj | add-Member -memberType NoteProperty -name Namespace -Value $parts[3]
		$retObj | add-Member -memberType NoteProperty -name SccmProvider -Value $sccmProviderLocation

		return $retObj
	}
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Get-SCCMObject {
	#  Generic query tool
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipelineByPropertyName=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="SCCM Class to query",ValueFromPipeline=$true)][Alias("Table","View")][String] $class,
		[Parameter(Mandatory=$false,HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		if ($Filter -eq $null -or $Filter -eq "")
		{
			Write-Verbose "WMI Query: SELECT * FROM $class"
			$retObj = get-wmiobject -class $class -computername $SccmServer.Machine -namespace $SccmServer.Namespace
		}
		else
		{
			Write-Verbose "WMI Query: SELECT * FROM $class WHERE $Filter"
			$retObj = get-wmiobject -query "SELECT * FROM $class WHERE $Filter" -computername $SccmServer.Machine -namespace $SccmServer.Namespace
		}

		return $retObj
	}
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Get-SCCMPackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_Package" -Filter $Filter
	}
}

Function Get-SCCMCollection {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_Collection" -Filter $Filter
	}
}

Function Get-SCCMAdvertisement {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_Advertisement" -Filter $Filter
	}
}

Function Get-SCCMDriver {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_Driver" -Filter $Filter
	}
}

Function Get-SCCMDriverPackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_DriverPackage" -Filter $Filter
	}
}

Function Get-SCCMTaskSequence {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_TaskSequence" -Filter $Filter
	}
}

Function Get-SCCMSite {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_Site" -Filter $Filter
	}
}

Function Get-SCCMImagePackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_ImagePackage" -Filter $Filter
	}
}

Function Get-SCCMOperatingSystemInstallPackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_OperatingSystemInstallPackage" -Filter $Filter
	}
}

Function Get-SCCMBootImagePackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_BootImagePackage" -Filter $Filter
	}
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function Get-SCCMComputer {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Filter on SCCM Resource ID",ValueFromPipelineByPropertyName=$true)][int32] $ResourceID = $false,
		[Parameter(Mandatory=$false, HelpMessage="Filter on Netbiosname on computer",ValueFromPipeline=$true)][String] $NetbiosName = "%",
		[Parameter(Mandatory=$false, HelpMessage="Filter on Domain name",ValueFromPipelineByPropertyName=$true)][Alias("Domain", "Workgroup")][String] $ResourceDomainOrWorkgroup = "%",
		[Parameter(Mandatory=$false, HelpMessage="Filter on SmbiosGuid (UUID)")][String] $SmBiosGuid = "%"
	)

	PROCESS {
		if ($ResourceID -eq $false -and $NetbiosName -eq "%" -and $ResourceDomainOrWorkgroup -eq "%" -and $SmBiosGuid -eq "%") {
			throw "Need at least one filter..."
		}

		if ($ResourceID -eq $false) {
			return Get-SCCMObject -sccmServer $SccmServer -class "SMS_R_System" -Filter "NetbiosName LIKE '$NetbiosName' AND ResourceDomainOrWorkgroup LIKE '$ResourceDomainOrWorkgroup' AND SmBiosGuid LIKE '$SmBiosGuid'"
		} else {
			return Get-SCCMObject -sccmServer $SccmServer -class "SMS_R_System" -Filter "ResourceID = $ResourceID"
		}
	}
}

Function Get-SCCMUser {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Filter on SCCM Resource ID",ValueFromPipelineByPropertyName=$true)][int32] $ResourceID = $false,
		[Parameter(Mandatory=$false, HelpMessage="Filter on unique username in form DOMAIN\UserName",ValueFromPipelineByPropertyName=$true)][String] $UniqueUserName = "%",
		[Parameter(Mandatory=$false, HelpMessage="Filter on Domain name",ValueFromPipelineByPropertyName=$true)][Alias("Domain")][String] $WindowsNTDomain = "%",
		[Parameter(Mandatory=$false, HelpMessage="Filter on UserName",ValueFromPipeline=$true)][String] $UserName = "%"
	)

	PROCESS {
		if ($ResourceID -eq $false -and $UniqueUserName -eq "%" -and $WindowsNTDomain -eq "%" -and $UserName -eq "%") {
			throw "Need at least one filter..."
		}

		if ($ResourceID -eq $false) {
			return Get-SCCMObject -sccmServer $SccmServer -class "SMS_R_User" -Filter "UniqueUserName LIKE '$UniqueUserName' AND WindowsNTDomain LIKE '$WindowsNTDomain' AND UserName LIKE '$UserName'"
		} else {
			return Get-SCCMObject -sccmServer $SccmServer -class "SMS_R_User" -Filter "ResourceID = $ResourceID"
		}
	}
}

Function Get-SCCMCollectionMembers {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="CollectionID", ValueFromPipeline=$true)][String] $CollectionID
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_CollectionMember_a" -Filter "CollectionID = '$CollectionID'"
	}
}

Function Get-SCCMSubCollections {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="CollectionID",ValueFromPipeline=$true)][Alias("parentCollectionID")][String] $CollectionID
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_CollectToSubCollect" -Filter "parentCollectionID = '$CollectionID'"
	}
}

Function Get-SCCMParentCollection {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="CollectionID",ValueFromPipeline=$true)][Alias("subCollectionID")][String] $CollectionID
	)

	PROCESS {
		$parentCollection = Get-SCCMObject -sccmServer $SccmServer -class "SMS_CollectToSubCollect" -Filter "subCollectionID = '$CollectionID'"

		return Get-SCCMCollection -sccmServer $SccmServer -Filter "CollectionID = '$($parentCollection.parentCollectionID)'"
	}
}

Function Get-SCCMSiteDefinition {
	# Get all definitions for one SCCM site
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer
	)

	PROCESS {
		Write-Verbose "Refresh the site $($SccmServer.SccmProvider.SiteCode) control file"
		Invoke-WmiMethod -path SMS_SiteControlFile -name RefreshSCF -argumentList $($SccmServer.SccmProvider.SiteCode) -computername $SccmServer.Machine -namespace $SccmServer.Namespace

		Write-Verbose "Get the site definition object for this site"
		return get-wmiobject -query "SELECT * FROM SMS_SCI_SiteDefinition WHERE SiteCode = '$($SccmServer.SccmProvider.SiteCode)' AND FileType = 2" -computername $SccmServer.Machine -namespace $SccmServer.Namespace
	}
}

Function Get-SCCMSiteDefinitionProps {
	# Get definitionproperties for one SCCM site
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer
	)

	PROCESS {
		return Get-SCCMSiteDefinition -sccmServer $SccmServer | ForEach-Object { $_.Props }
	}
}

Function Get-SCCMIsR2 {
	# Return $true if the SCCM server is R2 capable
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer
	)

	PROCESS {
		$result = Get-SCCMSiteDefinitionProps -sccmServer $SccmServer | ? {$_.PropertyName -eq "IsR2CapableRTM"}
		if (-not $result) {
			return $false
		} elseif ($result.Value = 31) {
			return $true
		} else {
			return $false
		}
	}
}

Function Get-SCCMCollectionRules {
	# Get a set of all collectionrules
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="CollectionID", ValueFromPipeline=$true)][String] $CollectionID
	)

	PROCESS {
		Write-Verbose "Collecting rules for $CollectionID"
		$col = [wmi]"$($SccmServer.SccmProvider.NamespacePath):SMS_Collection.CollectionID='$($CollectionID)'"

		return $col.CollectionRules
	}
}

Function Get-SCCMInboxes {
	# Give a count of files in the SCCM-inboxes
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Minimum number of files in directory")][int32] $minCount = 1
	)

	PROCESS {
		Write-Verbose "Reading \\$($SccmServer.Machine)\SMS_$($SccmServer.SccmProvider.SiteCode)\inboxes"
		return Get-ChildItem \\$($SccmServer.Machine)\SMS_$($SccmServer.SccmProvider.SiteCode)\inboxes -Recurse | Group-Object Directory | Where { $_.Count -gt $minCount } | Format-Table Count, Name -AutoSize
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function New-SCCMCollection {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Collection Name", ValueFromPipeline=$true)][String] $name,
		[Parameter(Mandatory=$false, HelpMessage="Collection comment")][String] $comment = "",
		[Parameter(Mandatory=$false, HelpMessage="Refresh Rate in Minutes")] [ValidateRange(0, 59)] [int] $refreshMinutes = 0,
		[Parameter(Mandatory=$false, HelpMessage="Refresh Rate in Hours")] [ValidateRange(0, 23)] [int] $refreshHours = 0,
		[Parameter(Mandatory=$false, HelpMessage="Refresh Rate in Days")] [ValidateRange(0, 31)] [int] $refreshDays = 0,
		[Parameter(Mandatory=$false, HelpMessage="Parent CollectionID")][String] $parentCollectionID = "COLLROOT"
	)

	PROCESS {
		# Build the parameters for creating the collection
		$arguments = @{Name = $name; Comment = $comment; OwnedByThisSite = $true}
		$newColl = Set-WmiInstance -class "SMS_Collection" -arguments $arguments -computername $SccmServer.Machine -namespace $SccmServer.Namespace

		# Hack - for some reason without this we don't get the CollectionID value
		$hack = $newColl.PSBase | select * | out-null

		# It's really hard to set the refresh schedule via Set-WmiInstance, so we'll set it later if necessary
		if ($refreshMinutes -gt 0 -or $refreshHours -gt 0 -or $refreshDays -gt 0)
		{
			Write-Verbose "Create the recur interval object"
			$intervalClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_ST_RecurInterval"
			$interval = $intervalClass.CreateInstance()
			if ($refreshMinutes -gt 0) {
				$interval.MinuteSpan = $refreshMinutes
			}
			if ($refreshHours -gt 0) {
				$interval.HourSpan = $refreshHours
			}
			if ($refreshDays -gt 0) {
				$interval.DaySpan = $refreshDays
			}

			Write-Verbose "Set the refresh schedule"
			$newColl.RefreshSchedule = $interval
			$newColl.RefreshType=2
			$path = $newColl.Put()
		}   

		Write-Verbose "Setting the new $($newColl.CollectionID) parent to $parentCollectionID"
		$subArguments  = @{SubCollectionID = $newColl.CollectionID}
		$subArguments += @{ParentCollectionID = $parentCollectionID}

		# Add the link
		$newRelation = Set-WmiInstance -Class "SMS_CollectToSubCollect" -arguments $subArguments -computername $SccmServer.Machine -namespace $SccmServer.Namespace

		Write-Verbose "Return the new collection with ID $($newColl.CollectionID)"
		return $newColl
	}
}

Function Add-SCCMCollectionRule {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true,  HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true,  HelpMessage="CollectionID", ValueFromPipelineByPropertyName=$true)] $collectionID,
		[Parameter(Mandatory=$false, HelpMessage="Computer name to add (direct)", ValueFromPipeline=$true)] [String] $name,
		[Parameter(Mandatory=$false, HelpMessage="WQL Query Expression", ValueFromPipeline=$true)] [String] $queryExpression = $null,
		[Parameter(Mandatory=$false, HelpMessage="Limit to collection (Query)", ValueFromPipeline=$false)] [String] $limitToCollectionId = $null,
		[Parameter(Mandatory=$true,  HelpMessage="Rule Name", ValueFromPipeline=$true)] [String] $queryRuleName
	)

	PROCESS {
		# Get the specified collection (to make sure we have the lazy properties)
		$coll = [wmi]"$($SccmServer.SccmProvider.NamespacePath):SMS_Collection.CollectionID='$collectionID'"

		# Build the new rule
		if ($queryExpression.Length -gt 0) {
			# Create a query rule
			$ruleClass = [WMICLASS]"$($SccmServer.SccmProvider.NamespacePath):SMS_CollectionRuleQuery"
			$newRule = $ruleClass.CreateInstance()
			$newRule.RuleName = $queryRuleName
			$newRule.QueryExpression = $queryExpression
			if ($limitToCollectionId -ne $null) {
				$newRule.LimitToCollectionID = $limitToCollectionId
			}

			$null = $coll.AddMembershipRule($newRule)
		} else {
			$ruleClass = [WMICLASS]"$($SccmServer.SccmProvider.NamespacePath):SMS_CollectionRuleDirect"

			# Find each computer
			$computer = Get-SCCMComputer -sccmServer $SccmServer -NetbiosName $name
			# See if the computer is already a member
			$found = $false
			if ($coll.CollectionRules -ne $null) {
				foreach ($member in $coll.CollectionRules) {
					if ($member.ResourceID -eq $computer.ResourceID) {
						$found = $true
					}
				}
			}
			if (-not $found) {
				Write-Verbose "Adding new rule for computer $name"
				$newRule = $ruleClass.CreateInstance()
				$newRule.RuleName = $name
				$newRule.ResourceClassName = "SMS_R_System"
				$newRule.ResourceID = $computer.ResourceID

				$null = $coll.AddMembershipRule($newRule)
			} else {
				Write-Verbose "Computer $name is already in the collection"
			}
		}
	}
}

Function Add-SCCMDirUserCollectionRule {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(ValueFromPipelineByPropertyName=$true)][String] $CollectionID,
		[Parameter(ValueFromPipeline=$true)][String] $UserName
	)

	PROCESS {
		$coll = [wmi]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_Collection.CollectionID='$CollectionID'"
		$ruleClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_CollectionRuleDirect"

		$RuleClass
		$UserRule=Get-SCCMUser "userName='$UserName'"
		$NewRuleName=$UserRule.name
		$NewRuleResourceID = $UserRule.ResourceID
		$newRule = $ruleClass.CreateInstance()

		$newRule.RuleName = $NewRuleName
		$newRule.ResourceClassName = "SMS_R_User"
		$newRule.ResourceID = $NewRuleResourceID

		$null = $coll.AddMembershipRule($newRule)
		$coll.requestrefresh()
		Clear-Variable -name oldrule -errorAction SilentlyContinue
		Clear-Variable -name Coll -errorAction SilentlyContinue
	}
}

Function New-SCCMPackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Package Name", ValueFromPipeline=$true)][String] $Name,

		[Parameter(Mandatory=$false, HelpMessage="Package Version")][String] $Version = "",
		[Parameter(Mandatory=$false, HelpMessage="Package Manufacturer")][String] $Manufacturer = "",
		[Parameter(Mandatory=$false, HelpMessage="Package Language")][String] $Language = "",
		[Parameter(Mandatory=$false, HelpMessage="Package Description")][String] $Description = "",
		[Parameter(Mandatory=$false, HelpMessage="Package Data Source Path")][String] $PkgSourcePath = "",
		[Parameter(Mandatory=$false, HelpMessage="Package Sharename")][String] $PkgShareName = ""
	)

	PROCESS {
		$packageClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_Package"
		$newPackage = $packageClass.createInstance() 

		$newPackage.Name = $Name
		if ($Version -ne "") 		{ $newPackage.Version = $Version }
		if ($Manufacturer -ne "") 	{ $newPackage.Manufacturer = $Manufacturer }
		if ($Language -ne "") 		{ $newPackage.Language = $Language }
		if ($Description -ne "") 	{ $newPackage.Description = $Description }

		if ($PkgSourcePath -ne "") {
			$newPackage.PkgSourceFlag = 2  # Direct (3 = Compressed)
			$newPackage.PkgSourcePath = $PkgSourcePath
			if ($PkgShareName -ne "") {
				$newPackage.ShareName = $PkgShareName
				$newPackage.ShareType = 2
			}
		} else {
			$newPackage.PkgSourceFlag = 1  # No source
			$newPackage.PkgSourcePath = $null
		}
		$newPackage.Put()

		$newPackage.Get()
		Write-Verbose "Return the new package with ID $($newPackage.PackageID)"
		return $newPackage
	}
}

Function New-SCCMAdvertisement {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true)] $AdvertisementName,
		[Parameter(Mandatory=$true)] $collectionID,
		[Parameter(Mandatory=$true)] $PackageID,
		[Parameter(Mandatory=$true)] $ProgramName,
		[Switch] $Download,
		[Parameter(Mandatory=$false, HelpMessage="YYYYMMDDhhmm")] $StartTime,
		[Parameter(Mandatory=$false, HelpMessage="YYYYMMDDhhmm")] $EndTime,
		[Parameter(Mandatory=$false, HelpMessage="YYYYMMDDhhmm")] $MandatoryTime
	)
	PROCESS {
		$strServer = $SccmServer.machine
		$strNamespace= $SccmServer.namespace
		$AdvClass = [WmiClass]("\\$strServer\" + "$strNameSpace" + ":SMS_Advertisement")
		if ($Download) {
			$RemoteClientFlags = "3152"
		} else {
			$RemoteClientFlags = "3208"
		}
		if ($StartTime -ne $null) {
			$PresentTime = $StartTime + "00.000000+***"
		} else {
			$PresentTime = "20200110000000.000000+***"
		}
		if ($EndTime -ne $null) {
			$ExpirationTime = $Endtime + "00.000000+***"
			$ExpirationTimeEnabled = $true
		} else {
			$ExpirationTime = "20200113000000.000000+***"
			$ExpirationTimeEnabled = $false
		}
		if ($MandatoryTime -ne $null) {
			$Deadline = $MandatoryTime + "00.000000+***"
		} else {
			$Deadline = $null
		}

		# Get the all the Advertisement Properties
		$newAdvertisement = $AdvClass.CreateInstance()
		$newAdvertisement.AdvertisementName = $AdvertisementName
		$newAdvertisement.CollectionID = $collectionID
		$newAdvertisement.PackageID = $PackageID
		$newAdvertisement.ProgramName = $ProgramName
		$newAdvertisement.RemoteClientFlags = $RemoteClientFlags
		$newAdvertisement.PresentTime = $PresentTime
		$newAdvertisement.ExpirationTime = $ExpirationTime
		$newAdvertisement.ExpirationTimeEnabled = $ExpirationTimeEnabled
		$newAdvertisement.Priority = "2"
		$newAdvertisement.IncludeSubCollection = $false

		# Create Advertisement
		$retval = $newAdvertisement.psbase.Put()
		if ($Deadline -ne $null) {
			# Create Mandatory Schedule
			$wmiClassSchedule = [WmiClass]("\\$strServer\" + "$strNameSpace" + ":SMS_ST_NonRecurring")
			$AssignedSchedule = $wmiClassSchedule.psbase.createinstance()
			$AssignedSchedule.starttime = $Deadline
			if ($Download) {
				$newAdvertisement.RemoteClientFlags = "9296"
			} else {
				$newAdvertisement.RemoteClientFlags = "9352"
			}
			$newAdvertisement.AssignedSchedule = $AssignedSchedule
			$newAdvertisement.AssignedScheduleEnabled = $true
			$newAdvertisement.psbase.put()
			$NewAdvertisementProperties = $newAdvertisement.AssignedSchedule
			foreach ($Adv in $NewAdvertisementProperties) {
				write-verbose "Created Advertisement. Name = $($newAdvertisement.AdvertisementName)"
				write-verbose "Created Advertisement. ID = $newAdvertisement"
				Write-Verbose "Mandatory Deadline created: $($Adv.StartTime)"
			}
		} else {
			write-verbose "Created Advertisement. Name = $($newAdvertisement.AdvertisementName)"
			write-verbose "Created Advertisement. ID = $newAdvertisement"
			write-verbose "No Mandatory-Deadline defined"
		}
	}
}

Function New-SCCMProgram {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Program Name")][String] $PrgName = "",
		[Parameter(Mandatory=$true, HelpMessage="Program PackageID")]$PrgPackageID,
		[Parameter(Mandatory=$false, HelpMessage="Program Comment")][String] $PrgComment = "",
		[Parameter(Mandatory=$false, HelpMessage="Program CommandLine")][String] $PrgCommandLine = "",
		[Parameter(Mandatory=$false, HelpMessage="Program MaxRunTime")]$PrgMaxRunTime,
		[Parameter(Mandatory=$false, HelpMessage="Program Diskspace Requirement")]$PrgSpaceReq,
		[Parameter(Mandatory=$false, HelpMessage="Program Working Directory")][String] $PrgWorkDir = "",
		[Parameter(Mandatory=$false, HelpMessage="Program Flags")] $PrgFlags
	)
	PROCESS {
		$programClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_Program"
		$newProgram = $programClass.createInstance()
		$newProgram.ProgramName = $PrgName
		$newProgram.PackageID = $PrgPackageID
		if ($PrgComment -ne "") { $newProgram.Comment = $PrgComment }
		if ($PrgCommandLine -ne "") { $newProgram.CommandLine = $PrgCommandLine }
		if ($PrgMaxRunTime -ne $null) { $newProgram.Duration = $PrgMaxRunTime} else { $newProgram.Duration = "0" }
		if ($PrgSpaceReq -ne $null) { $newProgram.DiskSpaceReq = $PrgSpaceReq }
		if ($PrgWorkDir -ne "") { $newProgram.WorkingDirectory = $PrgWorkDir }
		if ($PrgFlags -ne $null) { $newProgram.ProgramFlags = $PrgFlags} else { $newProgram.ProgramFlags = "135290880" }
		$newProgram.Put()
		$newProgram.Get()
		Write-Verbose "Return the new program for Package $($newProgram.PackageID)"
		return $newProgram
	}
}

Function Add-SCCMDistributionPoint {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="PackageID")][String] $DPPackageID,
		[Parameter(Mandatory=$false, HelpMessage="DistributionPoint Servername")][String]$DPName = "",
		[Parameter(Mandatory=$false, HelpMessage="All DistributionPoints of SiteCode")][String] $DPsSiteCode = "",
		[Parameter(Mandatory=$false, HelpMessage="Distribution Point Group")][String] $DPGroupName = "",
		[Switch] $AllDPs
	)
	PROCESS {
		if ($DPName -ne "") {
			$Resource = Get-SCCMObject -SccmServer $SccmServer -class SMS_SystemResourceList -Filter "RoleName = 'SMS Distribution Point' and Servername = '$DPName'"
			$DPClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_DistributionPoint"
			$newDistributionPoint = $DPClass.createInstance()
			$newDistributionPoint.PackageID = $DPPackageID
			$newDistributionPoint.ServerNALPath = $Resource.NALPath
			$newDistributionPoint.SiteCode = $Resource.SiteCode
			$newDistributionPoint.Put()
			$newDistributionPoint.Get()
			Write-Verbose "Assigned Package: $($newDistributionPoint.PackageID)"
		}
		if ($DPsSiteCode -ne "") {
			$ListOfResources = Get-SCCMObject -SccmServer $SccmServer -class SMS_SystemResourceList -Filter "RoleName = 'SMS Distribution Point' and SiteCode = '$DPsSiteCode'"
			$DPClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_DistributionPoint"
			$newDistributionPoint = $DPClass.createInstance()
			$newDistributionPoint.PackageID = $DPPackageID
			foreach ($resource in $ListOfResources) {
				$newDistributionPoint.ServerNALPath = $Resource.NALPath
				$newDistributionPoint.SiteCode = $Resource.SiteCode
				$newDistributionPoint.Put()
				$newDistributionPoint.Get()
				Write-Verbose "Assigned Package: $($newDistributionPoint.PackageID)"
			}
		}
		if ($DPGroupName -ne "") {
			$DPGroup = Get-SCCMObject -sccmserver $SccmServer -class SMS_DistributionPointGroup -Filter "sGroupName = '$DPGroupName'"
			$DPGroupNALPaths = $DPGroup.arrNALPath
			$DPClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_DistributionPoint"
			$newDistributionPoint = $DPClass.createInstance()
			$newDistributionPoint.PackageID = $DPPackageID
			foreach ($DPGroupNALPath in $DPGroupNALPaths) {
				$DPResource = Get-SCCMObject -SccmServer $SccmServer -class SMS_SystemResourceList -Filter "RoleName = 'SMS Distribution Point'" | Where-Object {$_.NALPath -eq $DPGroupNALPath}
				if ($DPResource -ne $null) {
					Write-Verbose "$DPResource"
					$newDistributionPoint.ServerNALPath = $DPResource.NALPath
					Write-Verbose "ServerNALPath = $($newDistributionPoint.ServerNALPath)"
					$newDistributionPoint.SiteCode = $DPResource.SiteCode
					Write-Verbose "SiteCode = $($newDistributionPoint.SiteCode)"
					$newDistributionPoint.Put()
					$newDistributionPoint.Get()
					Write-Host "Assigned Package: $($newDistributionPoint.PackageID) to $($DPResource.ServerName)"
				} else {
					Write-Host "DP not found = $DPGroupNALPath"
				}
			}
		}
		if ($AllDPs) {
			$ListOfResources = Get-SCCMObject -SccmServer $SccmServer -class SMS_SystemResourceList -Filter "RoleName = 'SMS Distribution Point'"
			$DPClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_DistributionPoint"
			$newDistributionPoint = $DPClass.createInstance()
			$newDistributionPoint.PackageID = $DPPackageID
			foreach ($resource in $ListOfResources) {
				$newDistributionPoint.ServerNALPath = $Resource.NALPath
				$newDistributionPoint.SiteCode = $Resource.SiteCode
				$newDistributionPoint.Put()
				$newDistributionPoint.Get()
				Write-Verbose "Assigned Package: $($newDistributionPoint.PackageID) $($newDistributionPoint.ServerNALPath)"
			}
		}
	}
}

Function Update-SCCMDriverPkgSourcePath {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Current Path", ValueFromPipeline=$true)][String] $currentPath,
		[Parameter(Mandatory=$true, HelpMessage="New Path", ValueFromPipeline=$true)][String] $newPath
	)

	PROCESS {
		Get-SCCMDriverPackage -sccmserver $SccmServer | Where-Object {$_.PkgSourcePath -ilike "*$($currentPath)*" } | Foreach-Object {
			$newSourcePath = ($_.PkgSourcePath -ireplace [regex]::Escape($currentPath), $newPath)
			Write-Verbose "Changing from '$($_.PkgSourcePath)' to '$($newSourcePath)' on $($_.PackageID)"
			$_.PkgSourcePath = $newSourcePath
			$_.Put() | Out-Null
		}
	}
}

Function Update-SCCMPackageSourcePath {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Current Path", ValueFromPipeline=$true)][String] $currentPath,
		[Parameter(Mandatory=$true, HelpMessage="New Path", ValueFromPipeline=$true)][String] $newPath
	)

	PROCESS {
		Get-SCCMPackage -sccmserver $SccmServer | Where-Object {$_.PkgSourcePath -ilike "*$($currentPath)*" } | Foreach-Object {
			$newSourcePath = ($_.PkgSourcePath -ireplace [regex]::Escape($currentPath), $newPath)
			Write-Verbose "Changing from '$($_.PkgSourcePath)' to '$($newSourcePath)' on $($_.PackageID)"
			$_.PkgSourcePath = $newSourcePath
			$_.Put() | Out-Null
		}
	}
}

Function Update-SCCMDriverSourcePathnotepad {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Current Path", ValueFromPipeline=$true)][String] $currentPath,
		[Parameter(Mandatory=$true, HelpMessage="New Path", ValueFromPipeline=$true)][String] $newPath
	)

	PROCESS {
		Get-SCCMDriver -sccmserver $SccmServer | Where-Object {$_.ContentSourcePath -ilike "*$($currentPath)*" } | Foreach-Object {
			$newSourcePath = ($_.ContentSourcePath -ireplace [regex]::Escape($currentPath), $newPath)
			Write-Verbose "Changing from '$($_.ContentSourcePath)' to '$($newSourcePath)' on $($_.PackageID)"
			$_.ContentSourcePath = $newSourcePath
			$_.Put() | Out-Null
		}
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# EOF

Examples

# List all available SCCM commands
Get-SCCMCommands

# Create an SCCM-Connection to the local server
$sccm = Connect-SCCMServer -Verbose

# Create a new collection with a querybased collection rule and a direct member
$newCollection = New-SCCMCollection -SccmServer $sccm -name "Some Collection Name" -Verbose
Add-SCCMCollectionRule -Server $sccm -collectionID $newRoot.CollectionId -queryExpression "SELECT * FROM SMS_R_System" -queryRuleName "All Systems" -Verbose
Add-SCCMCollectionRule -Server $sccm -collectionID $newRoot.CollectionId -name "COMPUTER123" -Verbose

# Count files in the inboxes
$sccm | Get-SCCMInboxes

# Get a package
$MyPackage = Get-SCCMPackage -server $sccm -filter "Name = 'Some Package Name'" 

Demo Webservice

A while ago I wrote a little PHP-application for demostrating webmonitors in System Center Operations Manager 2007.
It will probably work for any monitoring solution that catches http errorcodes or textstrings on a page.

Free to use, so give it a try. 🙂

You can find it at: http://snowland.se/demo/

Pimp my PXE-boot screen

It was “a few” years ago since I did use a HEX-editor… but with a little time over last night I did a small hack to the PXE-boot files.

Why I did it…
1. I wanted to test if I still know how to use a HEX-editor
2. I don’t like the original text.

Do I need to mention: This is NOT supported by anyone and if you break any deployment-solution… don’t blame me.

First, make a backup (*doh*).

The files you are looking for are located on your PXE-point, X:\RemoteInstall\SMSBoot\x86 (and \x64)

I use XVI32 v2.51 www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm to make the changes in the binary files.

Open up PXEBOOT.COM in XVI and search for “Press F12” (case sensitive).
Then replace the text. If you have a shorter text, fill it out with blank spaces. If you have a longer text… tough luck. :-\

"Press F12 for network service boot"
"Press F12 for snowland deployment "

The original text:
hexedit-press-f12

And the changed text:
hexedit-press-f12-snowland

Save and test to PXE-boot a machine.
(If you can’t see the new text, you probably need to copy the changed file to both the x86 and the x64 directory)

That wasn’t to hard, was it?
If it was… don’t bother to try the WDSNBP.COM-file. 😛

The largest textblock that a user can see is the following text, this is what we want to change / pimp.

The details below show the information relating to the PXE boot request for
This computer. Please provide these details to your Windows Deployment Services
Administrator so that this request can be approved.
         1         2         3         4         5         6         7         8
12345678901234567890123456789012345678901234567890123456789012345678901234567890

The easy way is just to change the text to something else, but why not use some ascii-art?

If you want to use ascii-art, the maximum width is 51 chars (the width of the third line) and 3 lines high since you need to replace and not add/delete anything.
Of course the first and second line can be a bit longer.

So… start up some texteditor with monospace font (notepad will do) and create some ascii-art.

   __  _  _  __  _    _ _    __  _  _ __
  (__  |\ | |  | |    | |   |__| |\ | |  \  Deployment Services is loading...
  .__) | \| |__|  \/\/  |__ |  | | \| |__/
         1         2         3         4         5         6         7         8
12345678901234567890123456789012345678901234567890123456789012345678901234567890

Now that we have some ascii-art with loads of blank spaces we need to replace the right number of spaces with something that we can see.

###__##_##_##__##_####_#_####__##_##_#__###################################
##(__##|\#|#|##|#|####|#|###|__|#|\#|#|##\##Deployment#Services#is#loading...##
##.__)#|#\|#|__|##\/\/##|__#|##|#|#\|#|__/#########
         1         2         3         4         5         6         7         8
12345678901234567890123456789012345678901234567890123456789012345678901234567890

The number of # should be exactly the same as the original text.

Start up XVI32 and load WDSNBP.COM, search for “The details below”… now comes the boring/tricky part. Replace the original text with your new ascii-art.

I did a small “translation”-file where I have the orignal row and the new row next to each other, like this for the second row.

This computer. Please provide these defails to your Windows Deployment Services
##(__##|\#|#|##|#|####|#|###|__|#|\#|#|##\##Deployment#Services#is#loading...##

Now you can see that the text “computer.” sould be replaced to ” |\ | | “. Yes, it will be hard to read and easy to do wrong.

There is a search/replace option in XVI32, if you use it remember: replace with the exact same number of characters.

Save, PXE-boot and enjoy… 🙂

The original:
f12-orginal

The final result:
f12-snowland

The MD5-hash of the WDSNBP.COM and PXEBOOT.COM-files in both x86 and x64 directories is the same so you only have to make the changes in one of them.
wdsnbp-md5-hash

Xperia

Atea_Pressmeddelanden

My first panel…

Shows the latest pressreleases from atea.se via a small webservice on snowland.se

Using PHP (MagpieRSS) on snowland.se and html, Javascript & CSS on the client.
The CAB is complied via “Xperia X1 html panel creator”.

Screendump

Download: Atea_Pressmeddelanden.cab

Twitter

The second one…

Another one… using Twitter API, MagpieRSS and some javascript.
Will keep it to myself since there is no configuration-option so it’s my Twitter-account only.
The CAB is complied via “Xperia X1 html panel creator”.

Screendump
screendump-twitter

Count files in SCCM-inboxes – Version 2

A bit more complex version of the last script

Requires a parameter for servername.

inboxcount.vbs

Option Explicit
Const cMinNofFiles = 1

Dim oFso, oArgs
Dim sPartOfPath, sServername, sSiteCode
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oArgs = WScript.Arguments

If oArgs.Count < 1 Then
	WScript.echo "ERROR: Missing argument!"
	WScript.Echo ""
	WScript.Echo "cscript.exe inboxCount.vbs SERVERNAME <part of path>"
	WScript.Quit -1
End If
sServername = uCase(oArgs.Item(0))
If oArgs.Count-1 = 1 Then
	sPartOfPath = oArgs.Item(1)
Else
	sPartOfPath = ""
End If

sSiteCode = getSccmSiteCode(sServername)

WScript.Echo "=============================================================================="
WScript.Echo " SCCM Inbox Counter                            Rikard Ronnkvist / snowland.se"
WScript.Echo "------------------------------------------------------------------------------"
WScript.Echo "   Server: " & sServerName
WScript.Echo " SiteCode: " & sSiteCode
WScript.Echo "     Path: \\" & sServername & "\SMS_" & sSiteCode & "\inboxes"
WScript.Echo "------------------------------------------------------------------------------"
ListFolders "\\" & sServername & "\SMS_" & sSiteCode & "\inboxes", "\\" & sServername & "\SMS_" & sSiteCode & "\inboxes"
WScript.Echo "=============================================================================="

WScript.Quit

Function getSccmSiteCode(sServername)
	Dim oWMIService, oLocator, oSites, currentSite
	
	Set oLocator = CreateObject("WbemScripting.SWbemLocator")
	Set oWMIService = oLocator.ConnectServer(sServername, "root\sms", "", "")

	' Now figure out the site code for this server.
	Set oSites = oWMIService.ExecQuery("SELECT SiteCode FROM SMS_ProviderLocation WHERE ProviderForLocalSite=true")

    For each currentSite in oSites
        getSccmSiteCode = Trim(currentSite.SiteCode)
        Exit Function
    Next
End Function

Sub ListFolders(sPath, sRoot)
	Dim oFolder, oFldr
	Set oFolder = oFSO.GetFolder(sPath)
	If (oFolder.Files.Count >= cMinNofFiles) AND (InStr(oFolder.Path, sPartOfPath) > 0) Then
		wscript.echo Left(oFolder.Files.Count & "        ", 6) & vbTab & Replace(uCase(oFolder.Path), uCase(sRoot), "")
	End If

	For Each oFldr In oFolder.SubFolders
		ListFolders oFldr.Path, sRoot
	Next
End Sub

Gadgets

Temperatur.nu

This gadget will read the current temperature from temperatur.nu

[rirov qver=version cver=310 qref=temperaturGadget]

Screenshot: Gadget
The Gadget

Screenshot: Settings Page
Settings page

Screenshot: Flyout
Flyout

Download:
Windows Live Download page (N/A)
snowland.se – riroTemperatur.gadget

Credits:
www.temperatur.nu

Forum:
www.temperatur.nu/forum/

History:
080213 – v1.0.0 – Initial release
080219 – v1.1.0 – Flyout
080303 – v1.2.0 – Bugfix (I hope) to autorefresh + Extra setting for refresh interval
080403 – v1.3.0 – Select-box for cities. Loads the “right” image from temperatur.nu. User can select what graph to show. Changes to the temperatur.nu-logo.
080404 – v1.3.1 – Testing a new way to AutoUpdate
081020 – v1.3.2 – Some small updates
090213 – v1.4.0 – With help from Joakim Arborelius, change from VBScript to JavaScript (Looks like it works better now)
101212 – v2.0.0 – (Almost) complete rewrite. Uses temperatur.nu API
110116 – v2.1.0 – MD5 signing of all API-calls
121124 – v3.0.0 – Probably the last version… Some more help from Joakim Arborelius, error handling
130119 – v3.1.0 – Centrum labeled as “C”, history in graphs added

riroMsure

This gadget will read the current temperature from your own 1-Wire devices, if you use MSure and the userexit module that is in the zip-file.

Screenshot:
The Gadget

Download:
snowland.se – riroMsureGadget.gadget

History:
090330 – v1.0.0 – Initial release

HashTag Reader #TEE09

Screenshot:
The Gadget

Download:
snowland.se – riroHashTagReaderTEE09.gadget

FYI: On the move…

snowland.se is on the move.

I am changing webhost for snowland.se so if you get som 404 or any other error… you know why.

Why the change? I’m collecting all my domains to one host.

Changing to Surftown

snowland.se v2.0

Ok som ni kanske ser så har siten bytt tema och om någon rad även språk.

Announcing snowland v2.0
– Change of this site from swedish to english
– New theme
– Some small updates (mainly bug’s)

To-do-list
– Translate the static pages

Might-do-list
– Translate the older posts

Microsoft Management Summit 2007

Okej, man borde skriva en hel massa om vad som har hänt och alla seminarier. Men det tänker jag inte göra.
Det finns femtielva bloggar som har skrivit som tokar och att bara upprepa en massa känns måttligt intressant.

Har ni missat någonting så har Techlog-gänget skrivit en samanfattning på www.techlog.nl

En sak som däremot kan vara bra att ha är dessa 3 keynotes:
Bob Muglia
Kirill Tatarinov
Customer and Partner Panel Discussion

Ska jag göra en liten samanfattning så blir det nog: Bra. Inte bäst men bra.

Written by Comments Off on Microsoft Management Summit 2007 Posted in Snowland.se Tagged with