I am trying to deploy an OVA file using powershell script. I found a script from internet and modified it a little bit and execute. During execution at Import-VApp command i am seeing this error: Import-VApp Line 157: Duplicate element 'AddressOnParent'.
I am able to deploy the OVA manually. But thru this script, i am seeing this error. Any help would be appreciated.
Please find my powershell script below. (keeping only important script below, per suggestion).
param(
)
#---- Custom OVA Properties ::> START <:: ----- #
$vAPPPropertyId_ip4enable = "IPv4 Enable"
$vAPP_ip4enable = "True"
$vAPPPropertyId_ip4address = "IPv4 Address"
$vAPP_ip4address = "10.51.98.20"
$vAPPPropertyId_ip4netmask = "IPv4 Netmask"
$vAPP_ip4netmask = "255.255.255.0"
$vAPPPropertyId_ip4gateway = "Ipv4 Gateway"
$vAPP_ip4gateway = "10.51.98.1"
$vAPPPropertyId_ip6enable = "Ipv6 Enable"
$vAPP_ip6enable = "False"
#$vAPPPropertyId_ip6address = "IPv6 Address"
#$vAPP_ip6address = ""
#$vAPPPropertyId_ip6gateway = "IPv6 Gateway"
#$vAPP_ip6gateway = ""
$vAPP_defaultRouteKey = 1
$vAPP_defaultRouteCmd = ""
#---- Custom OVA Properties ::> END <:: ----- #
$rp = Get-ResourcePool -name $resourcePool
Write-Host " Resoure Pool = $rp"
$cluster = $rp.ExtensionData.Owner
$vhost = (Get-Cluster -Id $cluster).ExtensionData.Host[0]
Write-Host " VHost = $vhost "
$VMHost = Get-VMHost -Id $vhost
Write-Host " VMHost = $VMHost "
if ($PortProfile -ne "")
{$PortgroupId = Get-VirtualPortGroup -Name $PortProfile -Distributed -VMHost (Get-VMHost $VMHost)}
Write-host "PortGroup = $PortgroupId"
Write-Host "Importing VApp .... "
$ovalocation = "C:\Script\s42700x8_1_1_a2.ova"
Write-Host "vAppName = $vAppName"
$vms = Import-VApp -Source $ovalocation -Name $vAppName -VMHost $VMHost #-Location $rp -Datastore $ds
#$vms = Import-VApp -Source $ovalocation -Name $vAppName -Location $rp -VMHost $VMHost -Datastore $ds
}
finally {
disconnect-VIServer -Confirm:$false
}
Output looks like this:
PS C:\Users\Administrator> C:\Script\OvaTestFile2.ps1
9/22/2014 3:23:58 AM Import-VApp Line 157: Duplicate element 'AddressOnParent'.
Related
I'm trying to expose an endpoint using RestPS routes in powershell. I was able to expose it and run a custom PS script when an endpoint (http://localhost:8080/scan) is hit.
How do we pass body through routes & based on that value I need to execute the custom script.
RestPSroutes.json - Example
{
"RequestType": "GET",
"RequestURL": "/scan",
"RequestCommand": "C:/RR/api-compliance.ps1" }
snippet from the above script (api-compliance.ps1) ;
###############
# Setup Creds #
###############
$userID = "****"
$Pass = "*****"
#$Creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $userID,$Pass
$vCenter = "vCenter01"
$cluster = "Cluster01"
$vmhost = "Host01"
$bl = "Baseline01"
######################
# Connect to vCenter #
######################
Connect-VIServer $VCTRs -user $userID -password $Pass -WarningAction SilentlyContinue -Force
$baseline = Get-Baseline | ? {$_.name -eq $bl}
$baseline | Attach-Baseline -Entity $vmhost -Confirm:$false
Scan-Inventory -Entity $vmhost
Right now we are hardcoding the below values
$vCenter = "vCenter01"
$cluster = "Cluster01"
$vmhost = "Host01"
But we want these to be passed as a request body. Can someone help?
Simply declare parameters $RequestArgs and $Body in the target script/function, and RestPS will automatically pass the appropriate values along as strings:
param(
[string]$RequestArgs,
[string]$Body
)
$RequestArgs.Split('&') |ForEach-Object {
$paramName,$paramValue = $_.Split('=')
Write-Host "Received query parameter ${paramName} with value '$paramValue'"
}
We are using Microsoft HPC (High performance computing). When a job is running, I want to see various HPC metrics and publish them onto AWS Cloudwatch. Below is the script that was on AWS site. Entire script runs fine but the last line which tries to write to Cloudwatch fails.
Did anyone get this error?
Write-CWMetricData : A WebException with status NameResolutionFailure was thrown.
At D:\temp\HPCMetricstest.ps1:81 char:1
+ Write-CWMetricData -Namespace "HPC Cluster Metrics" -MetricData $m1,
$m2, $m3, $ ...
+ CategoryInfo : InvalidOperation:
(Amazon.PowerShe...etricDataCmdlet:WriteCWMetricDataCmdlet) [Write-CWM
etricData], InvalidOperationException
+ FullyQualifiedErrorId :mazon.Runtime.AmazonServiceException,Amazon.PowerShell.Cmdlets.CW.WriteCWMetricDataCmdl
et
#
# This PowerShell script computes metrics on the head node of an HPC
Pack cluster and publishes them to Amazon CloudWatch
#
# It must be called with the current region and stack name
# Properties of HPC Nod: NetBiosName, HealthState, State, Groups
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,Position=1)]
[string]$Region,
[Parameter(Mandatory=$True,Position=2)]
[string]$Stack
)
Add-PSSnapIn Microsoft.HPC
Import-Module AWSPowerShell
$jobs = (Get-HpcJob -State Queued, Running -ErrorAction SilentlyContinue)
$tasks = ($jobs | Get-HpcTask -State Running, Queued -ErrorAction SilentlyContinue)
$nodes = (Get-HpcNode -GroupName ComputeNodes -State Online)
$jobCount = $jobs.Count
$taskCount = $task.Count
$coreHours = ($tasks | % { $_.Runtime.TotalHours * $_.MinCores } |
Measure-Object -Sum | Select-Object -ExpandProperty Sum)
$nodeCount = $nodes.Count
$coresPerMachine = ($nodes | Measure-Object -Property SubscribedCores -Average | Select-Object -ExpandProperty Average)
Write-Host "Cores per machine basam " $coresPerMachine
$machineHours = [System.Math]::Ceiling($coreHours / $coresPerMachine)
$globalHours = [System.Math]::Ceiling($machineHours / $nodeCount)
Function CreateMetric
{
param([string]$Name, [string]$Unit="Count", [string]$Value="0",
[string]$StackId, [System.DateTime]$When = (Get-
Date).ToUniversalTime())
$dim = New-Object Amazon.CloudWatch.Model.Dimension
$dim.Name = "StackId"
$dim.Value = $StackId
$dat = New-Object Amazon.CloudWatch.Model.MetricDatum
$dat.Timestamp = $When
$dat.MetricName = $Name
$dat.Unit = $Unit
$dat.Value = $Value
#Write-Host $dat.MetricName $dat.Value $dat.Unit $dat.Timestamp
$dat.Dimensions = New-Object -TypeName System.Collections.Generic.List[Amazon.CloudWatch.Model.Dimension]
$dat.Dimensions.Add($dim)
$dat
}
$now = (Get-Date).ToUniversalTime()
$m1 = (CreateMetric -Name "Job Count" -Value "$jobCount" -StackId
$Stack -When $now)
$m2 = (CreateMetric -Name "Task Count" -Value "$taskCount" -StackId
$Stack -When $now)
$m3 = (CreateMetric -Name "Core Hours" -Value "$coreHours" -StackId
$Stack -When $now)
$m4 = (CreateMetric -Name "Node Count" -Value "$nodeCount" -StackId
$Stack -When $now)
$m5 = (CreateMetric -Name "Cores Per Machine" -Value
"$coresPerMachine" -StackId $Stack -When $now)
$m6 = (CreateMetric -Name "Machine Hours" -Value "$machineHours" -
StackId $Stack -When $now)
$m7 = (CreateMetric -Name "Global Hours" -Value "$globalHours" -
StackId $Stack -When $now)
#Next line I am getting issue
Write-CWMetricData -Namespace "HPC Cluster Metrics" -MetricData
$m1, $m2, $m3, $m4, $m5, $m6, $m7 -Region $Region
In the AWS Tools for PowerShell, "A WebException with status NameResolutionFailure was thrown." often means that you've specified the region incorrectly. This is because the region is used to resolve DNS for the backing web service you're trying to hit, in this case the CloudWatch service for your given region.
See the documentation for a list of valid regions, or comment here with the region you attempted to use and we can help you pick the right one.
Further Reading
AWS PowerShell Documentation - Specifying AWS Regions
I am having difficulty outputting a variable on the same line as a string of text. It works when I use Write-Host, but not Write-Output. I want to use Write-Output because it is seemingly the best practice (keeping things in the pipeline), but Write-Output always outputs the variable on a newline.
The line of code that I am having trouble with is:
Write-Host $VM "- VM name not valid: check the input file for spelling errors."
Also, I am fairly new to PowerShell scripting so I welcome any other input on this script.
Function Get-VMSwapping {
#requires –version 3.0
<#
.SYNOPSIS
Outputs the following: Cluster, VMHost, VM, SwappedMemory, BalloonedMemory.
.DESCRIPTION
Outputs the following: Cluster, VMHost, VM, SwappedMemory, BalloonedMemory.
Make sure to be connected to the vCenter server that has all of the VMs to enumerate.
.NOTES
Author: Nick Sousa
Date: Jan 28, 2014
Version: 1.0
#>
[CmdletBinding(
HelpURI='https://www.vmware.com/support/developer/PowerCLI/',
SupportsShouldProcess=$true,
ConfirmImpact="High"
)]
Param(
[ValidateScript({
If(Test-Path -Path $_) {$true}
Else {Throw "Input filename is not valid."}
})]
[Parameter(Mandatory=$false, ParameterSetName="InputFile",Position = 0)][string]$InputFile
)
Begin {
$ErrorActionPreference = "Stop"
} # End "Begin"
Process {
Try {
If($PSCmdlet.ShouldProcess("VMs that are ballooning & swapping")) {
If($PSBoundParameters.ContainsKey('InputFile')) {
$VMReport = #()
# Loop through each item in the file specified in -InputFile.
# If the VM cannot be validated with Get-VM, write an error to the screen.
# If the VM is found within vCenter, output its Swap/Balloon amounts.
ForEach($VM in Get-Content -Path $InputFile) {
If(Get-VM -Name $VM -ErrorAction SilentlyContinue) {
$VMFull = Get-VM -Name $VM
$VMName = $VMFull.Name
$VMView = Get-View -ViewType VirtualMachine -Filter #{"Name" = "^$VMName$"}
$obj = "" | Select-Object Cluster, VMHost, VM, SwappedMemory, BalloonedMemory
$obj.Cluster = $VMFull.Host.Parent.Name
$obj.VMHost = $VMFull.Host.Name
$obj.VM = $VMView.Name
$obj.SwappedMemory = $VMView.Summary.QuickStats.SwappedMemory
$obj.BalloonedMemory = $VMView.Summary.QuickStats.BalloonedMemory
$VMReport += $obj
} # End "If(Get-VM -Name $VM)"
Else {
Write-Host $VM "- VM name not valid: check the input file for spelling errors."
} # End Else for "If(Get-VM -Name $VM)"
} # End "ForEach($VM in $VMs)"
$VMReport | Format-Table -AutoSize
} # End "If($PSBoundParameters.ContainsKey('InputFile'))"
Else {
# Pull a list of all VMs that have Balloon Memory greater than 0.
# Loop through all VMs found and prepare a collection object to be outputted.
$VMReport = #()
$VMs = Get-View -ViewType VirtualMachine | Where-Object {$_.Summary.QuickStats.BalloonedMemory -ne "0"}
ForEach($VM in $VMs) {
$VMFull = Get-VM -Name $VM.Name
$obj = "" | Select-Object Cluster, VMHost, VM, SwappedMemory, BalloonedMemory
$obj.Cluster = $VMFull.Host.Parent.Name
$obj.VMHost = $VMFull.Host.Name
$obj.VM = $VM.Name
$obj.SwappedMemory = $vm.Summary.QuickStats.SwappedMemory
$obj.BalloonedMemory = $vm.Summary.QuickStats.BalloonedMemory
$VMReport += $obj
} # End "ForEach($VM in $VMs)"
$VMReport | Format-Table -AutoSize
} # End Else for "If($PSBoundParameters.ContainsKey('InputFile'))"
} # End "If($PSCmdlet.ShouldProcess("VMs that are ballooning & swapping"))"
} # End "Try"
Catch {
Write-Output "Caught an exception:"
Write-Output "Exception Type: $($_.Exception.GetType().FullName)"
Write-Output "Exception Message: $($_.Exception.Message)"
} # End "Catch"
Finally {
$ErrorActionPreference = "Continue"
} # End "Finally"
} # End "Process"
} # End "Function Get-VMSwapping"
Concatenate the string
Write-Output ($VM + "- VM name not valid: check the input file for spelling errors.")
I'm trying to script (powershell/powercli) the cloning of our QA environment (261 servers).
Basically I want to make a new copy of each server just changing the VM name, the hostname, and the IP address. Ideally I'd want the new clone on the domain (90% of them are Windows OS). And many of my servers have many large hard drives that won't all fit on one datastore so I have to be able to clone to multiple datastores.
I started off with New-VM for the servers that were small enough to fit on one datastore, but OSCustomization only works about 30% of the time. The rest of the time I have to login to Windows and manually remove from the domain to rename the hostname. Most of the time Set-OSCustomizationNicMapping works But specifying -Domain -DomainUsername/Password never works (at best it renames the server and puts in the "domain-name" workgroup but it never joins it to the domain).
To workaround the multidatastore issue I discovered $vm.ExtensionData.CloneVM using VMWare.Vim.VirtualMachineRelocateSpec to specify which hard drives go to which datastores and that works great, but I don't know how to customize the hostname or NIC settings.
So the basic requirements are: clone to multiple datastores changing hostname and IP settings. Does anyone have any recommendations or solutions?
Here's some of my code snippets:
Setting up the OSCustomizationSpec for New-VM
$spec = New-OSCustomizationSpec -Name "PowerCLI Scripting for $NewHostName" -Spec "PowerCLI Scripting" -WhatIf:$False
Set-OSCustomizationSpec $spec -Workgroup "WORKGROUP" -DomainUsername "qajoin#qa.company.com" -DomainPassword (Get-Password -Username "qa\qajoin") -ProductKey $ProductKey -AdminPassword (Get-Password $Script:LuserName) | Out-Null
Get-OSCustomizationSpec "PowerCLI Scripting for $NewHostName" `
| Get-OSCustomizationNicMapping `
| Set-OSCustomizationNicMapping `
-IPMode:UseStaticIP `
-IPAddress $NewIPAddress `
-SubnetMask "255.255.248.0" `
-DNS "10.26.40.115","10.26.40.116" `
-DefaultGateway $NewDFGW | Out-Null
The New-VM command:
$VM = New-VM -VMHost $VMHost -VM $Hostname -Name $NewHostName -Description "$Description" -OSCustomizationSpec "PowerCLI Scripting for $NewHostName" -Location (Get-Folder -Id $Location) -Datastore $MostFreeSpace -ErrorAction Stop
Here's the multi-datastore clone:
$VMXtargetDatastore = Get-Datastore ($MapInfo | Where-Object {$_.Name -eq "Hard disk 1"}).NewDataStore
#Create an empty CloneSpec
$spec = New-Object VMware.Vim.VirtualMachineCloneSpec
$spec.Template = $false
$spec.PowerOn = $false
#Create a RelocateSpec (datastore is target for .vmx)
$spec.Location = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.Location.Datastore = $targetDatastore.ExtensionData.MoRef
#For each disk in the current vm
# create a new DiskLocator spec
# populate the datastore and diskid from the current harddisk
# add the spec to RelocateSpec from above
Get-HardDisk -VM $Origvm | %{
$disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$disk.diskId = $_.ExtensionData.Key #2001,2002,2003,...
$DiskLabel = $_.ExtensionData.DeviceInfo.Label
#$disk.datastore = $_.ExtensionData.Backing.Datastore #type=datastore value=datastore-2790
$dsname = ($MapInfo | Where-Object {$_.Name -eq $DiskLabel}).NewDataStore
$ds = Get-Datastore -Name $dsname
$disk.datastore = $ds.id
$spec.Location.Disk += $disk
}
$CustSpec = New-Object VMware.Vim.CustomizationSpec
$origvm.ExtensionData.CloneVM((Get-Folder -Id $folder).ExtensionData.MoRef, $targetName, $spec)
I'm guessing the next step using the ExtensionData.CloneVM method is to declare a new object of CustomizationIdentitySettings but the documentation (http://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.IdentitySettings.html) that I could find isn't really helpful (probably because the settings vary by OS?) and then add that object to my $spec object.
Same would go for OSCustomizationNicMapping (http://www.vmware.com/support/developer/PowerCLI/PowerCLI41U1/html/OSCustomizationNicMapping.html) but I can't suss enough information out of the pubs to figure out how to build my $spec object.
Can't you copy to an isolated environment? Just build a set of extra (isolated) VLANs and copy all VMs, keep IP/Names, only switch the VLAN at the VM level.
I finally found this page: http://www.vmdev.info/?p=202
I started with the example they show and it worked, so I kept adding in CloneSpec fields until I got what I wanted:
$nicMaparray = #()
$FirstNic = New-Object VMware.Vim.CustomizationAdapterMapping
$FirstNic.adapter = New-Object VMware.Vim.CustomizationIPSettings
$FirstNic.adapter.dnsDomain = $domain
$FirstNic.adapter.dnsServerList = "10.26.40.115","10.26.40.116"
$FirstNic.adapter.gateway = $DefGW
$FirstNic.adapter.ip = New-Object Vmware.Vim.CustomizationFixedIp
$FirstNic.adapter.ip.IpAddress = $NewIP
$FirstNic.adapter.subnetMask = "255.255.248.0"
$nicMaparray += $FirstNic
$folderobj = $origvm.parent
$vm = Get-VM $sourceName | Get-View
$cloneName = $targetName
$cloneFolder = Convert-PathToFolderObject -FolderPath $folderpath
$cloneSpec = new-object Vmware.Vim.VirtualMachineCloneSpec
$cloneSpec.Location = new-object Vmware.Vim.VirtualMachineRelocateSpec
$cloneSpec.Location.Host = (Random(Get-VMHost | Where {$_.Name -like "*esxiqa*"}) | get-view).MoRef
$targetDatastore = ($MapInfo | Where-Object {$_.Name -eq "Hard disk 1"}).NewDataStore
$cloneSpec.Location.Datastore = (Get-Datastore $targetDatastore | get-view).MoRef
$cloneSpec.customization = New-Object VMware.Vim.CustomizationSpec
$cloneSpec.customization.globalIPSettings = New-Object VMware.Vim.CustomizationGlobalIPSettings
$cloneSpec.customization.globalIPSettings.dnsServerList = "10.26.40.115","10.26.40.116"
$cloneSpec.customization.identity = New-Object VMware.Vim.CustomizationSysprep
# $spec.customization.identity.guiRunOnce = New-Object VMware.Vim.CustomizationGuiRunOnce
$cloneSpec.customization.identity.guiUnattended = New-Object VMware.Vim.CustomizationGuiUnattended
$cloneSpec.customization.identity.guiUnattended.autoLogonCount = 0
$cloneSpec.customization.identity.guiUnattended.password = New-Object VMware.Vim.CustomizationPassword
$cloneSpec.customization.identity.guiUnattended.password.plainText = $true
$cloneSpec.customization.identity.guiUnattended.password.value = Get-Password -Username "Administrator"
$cloneSpec.customization.identity.identification = New-Object VMware.Vim.CustomizationIdentification
$cloneSpec.customization.identity.identification.joinWorkgroup = "WORKGROUP"
# $spec.customization.identity.licenseFilePrintData = $null
$cloneSpec.customization.identity.userData = New-Object VMware.Vim.CustomizationUserData
$cloneSpec.customization.identity.userData.computerName = New-Object VMware.Vim.CustomizationFixedName
$cloneSpec.customization.identity.userData.computerName.name = $cloneName
$cloneSpec.customization.identity.userData.productID = $ProductKey
$cloneSpec.customization.nicSettingMap = $nicMaparray
#nicMaparray build above
# $cloneSpec.customization.options = $null
$cloneSpec.powerOn = $true
Get-HardDisk -VM $sourceName | %{
$disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$disk.diskId = $_.ExtensionData.Key #2001,2002,2003,...
$DiskLabel = $_.ExtensionData.DeviceInfo.Label
$dsname = ($MapInfo | Where-Object {$_.Name -eq $DiskLabel}).NewDataStore
$ds = Get-Datastore -Name $dsname
$disk.datastore = $ds.id
$cloneSpec.Location.Disk += $disk
}
Write-Verbose "Cloning $sourceName"
try
{
$vm.CloneVM( $cloneFolder, $cloneName, $cloneSpec)
return $true
}
catch
{
$_.Exception
return $false
}
I have the following code, but I get an "Invalid Namespace" error constantly, I am pretty sure I am entering the correct information.
If you have another way of doing this, it's also accepted.
Param(
$SiteCode,
$SourceFile,
$Destination = "$env:USERPROFILE\DESKTOP\Computers.csv"
)
$Computers = Get-Content $SourceFile
$EmptyArray = #()
foreach($computer in $computers)
{
$ResourceIDQuery = Get-WmiObject -Namespace "root\sms\site_$SiteCode" -Class SMS_R_SYSTEM -Filter "Name='$computer'"
$CollectionQuery = Get-WmiObject -Namespace "root\sms\site_$SiteCode" -Class SMS_CollectionMember_a -filter "ResourceID='$($ResourceIDQuery.ResourceId)'"
foreach($Item in $CollectionQuery)
{
$DObject = New-Object PSObject
$Dobject | Add-Member -MemberType NoteProperty -Name "Computer" -Value $computer
$Dobject | Add-Member -MemberType NoteProperty -Name "ResID" -Value $($ResourceIDQuery.ResourceId)
$Dobject | Add-Member -MemberType NoteProperty -Name "CollID" -Value $($Item.CollectionId)
$Dobject | Add-Member -MemberType NoteProperty -Name "DirectOrNot" -Value $($Item.IsDirect)
$EmptyArray += $Dobject
}
}
$EmptyArray | ConvertTo-Csv -NoTypeInformation | Out-File $Destination
Rather than connecting to each computer and extracting the information (slow) get it from the straight from the database....
[CmdletBinding()]
param (
[string] $hosts = "",
[string] $sccmsrv = "",
[Parameter(Mandatory=$False,Position=3)]
[string] $path = ""
)
$usage = "USAGE: List-AdvertCollMembershipSCCM.ps1 -sccmsrv SCCMSERVER -hosts 'host1 host2 host3' -path 'c:\temp\Outfile.csv'"
if ($host -and $sccmsrv){
Write-Host ""
Write-Host -ForegroundColor Yellow "SCCM Server: $sccmsrv"
Write-Host -ForegroundColor Yellow "Looking at hosts: $hosts"
#### Function for executing a SQL query with integrated authentication
function execSQLQuery ([string]$fSQLServer, [string]$db, [string]$query){
$objConnection = New-Object System.Data.SqlClient.SqlConnection
$objConnection.ConnectionString = "Server = $fSQLServer; Database = $db; trusted_connection=true;"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand $query, $objConnection
trap {Write-Host -ForegroundColor 'red' "($sqlsrv/$db not accessible)";continue}
$SqlCmd.Connection.Open()
if ($SqlCmd.Connection.State -ine 'Open') {
$SqlCmd.Connection.Close()
return
}
$dr = $SqlCmd.ExecuteReader()
#get the data
$dt = new-object "System.Data.DataTable"
$dt.Load($dr)
$SqlCmd.Connection.Close()
$dr.Close()
$dr.Dispose()
$objConnection.Close()
return $dt
}
# read the SCCM site name of the SCCM site server
$site = (gwmi -ComputerName $sccmsrv -Namespace root\sms -Class SMS_ProviderLocation).sitecode
# enumerating SQL server name for the given SCCM site server
$sccmCompquery = gwmi -q "Select distinct SiteSystem, Role, SiteCode FROM SMS_SiteSystemSummarizer where role = 'SMS SQL Server' and siteCode = '$site' ORDER BY SiteCode" -namespace "root\sms\site_$site" -ComputerName $sccmsrv
[string]$tmpstr = [regex]::Match($sccmCompquery.sitesystem, "\\\\\w+\\$")
$sccmSQLServer = $tmpstr.replace("\", "")
$objColl = #()
#### Collate the host list.
$hostlist = #($Input)
if ($hosts) {
if($hosts -imatch " "){
$hostsArr = #($hosts.split(" "))
$hostlist += $hostsArr
}
else{
$hostlist += $hosts
}
}
# going through the list of hosts
foreach($srv in $hostlist){
$memberQuery = "SELECT dbo.v_FullCollectionMembership.Name AS 'Hostname', dbo.v_GS_SYSTEM.ResourceID, dbo.v_Collection.Name AS 'Collection Name', dbo.v_Collection.CollectionID, dbo.v_FullCollectionMembership.IsDirect "
$memberQuery += "FROM dbo.v_FullCollectionMembership INNER JOIN dbo.v_Collection ON dbo.v_FullCollectionMembership.CollectionID = dbo.v_Collection.CollectionID INNER JOIN dbo.v_GS_SYSTEM ON dbo.v_FullCollectionMembership.ResourceID = dbo.v_GS_SYSTEM.ResourceID "
$memberQuery += "WHERE (LOWER(dbo.v_FullCollectionMembership.Name) = LOWER('$srv'))"
# running sql query to enumerate list of collections the computer is member of
$membership = execSQLQuery $sccmSQLServer "SMS_$site" $memberQuery
# if we have a result, go through it and build an object collection with the computer name and the collection(s) it is member of
if($membership){
foreach($enumColl in $membership){
$sObject = $enumColl | select Hostname, ResourceID, "Collection Name", CollectionID, IsDirect
$objColl +=$sObject
}
}
}
if ($objColl){
if ($path){
$objColl | ft -AutoSize
Write-Host -ForegroundColor Yellow "Exporting to results to: $path"
$objColl | Export-Csv $path -NoTypeInformation
}
else{
$objColl | ft -AutoSize
Write-Host -ForegroundColor Green "Use the -path argument in the command line to export output to csv to display"
Write-Host -ForegroundColor Green "the 'IsDirect' Information"
Write-Host ""
}
}
Else {
foreach ($Hostname in $hostlist){
Write-Host ""
Write-Host -ForegroundColor Yellow "The host $hostname is not a member of any collection"
}
Write-Host -ForegroundColor Yellow "Check you have entered the correct hostname and try again"
}
}
else {
Write-Host ""
Write-Host -ForegroundColor Yellow $usage
}
Execution:-
PS C:\> ListSCCMCollections.ps1 -sccmsrv SCCMSERVER -hosts host1,host2,host3 -path "c:\temp\Outfile.csv"
or
PS C:\> Get-Content hostlist.txt | ListSCCMCollections.ps1 -sccmsrv SCCMSERVER -path c:\temp\Outfile.csv
Getting the requested info straight from SQL:-
SELECT dbo.v_FullCollectionMembership.Name AS 'Hostname', dbo.v_GS_SYSTEM.ResourceID, dbo.v_Collection.Name AS 'Collection Name', dbo.v_Collection.CollectionID,
dbo.v_FullCollectionMembership.IsDirect
FROM dbo.v_FullCollectionMembership INNER JOIN
dbo.v_Collection ON dbo.v_FullCollectionMembership.CollectionID = dbo.v_Collection.CollectionID INNER JOIN
dbo.v_GS_SYSTEM ON dbo.v_FullCollectionMembership.ResourceID = dbo.v_GS_SYSTEM.ResourceID
WHERE (LOWER(dbo.v_FullCollectionMembership.Name) = LOWER('Hostname'))
This script can be used with any SQL query on the SCCM database. All you need to do is update the SQL query in the script. i.e. the $memberQuery array (if you spread the query over a couple of lines like below, be sure to leave a space at the end of each line with exception to the last).
For example; If you'd like the script to show the clients collections with live advertisements assigned to them change the SQL query in the $memberQuery array to:-
$memberQuery = "SELECT dbo.v_FullCollectionMembership.Name AS 'Hostname', dbo.v_GS_SYSTEM.ResourceID, dbo.v_Collection.Name AS 'Collection Name',dbo.v_Collection.CollectionID, dbo.v_FullCollectionMembership.IsDirect, dbo.v_Advertisement.AdvertisementID, dbo.v_Advertisement.AdvertisementName "
$memberQuery += "FROM dbo.v_FullCollectionMembership INNER JOIN dbo.v_Collection ON dbo.v_FullCollectionMembership.CollectionID = dbo.v_Collection.CollectionID INNER JOIN dbo.v_GS_SYSTEM ON dbo.v_FullCollectionMembership.ResourceID = dbo.v_GS_SYSTEM.ResourceID INNER JOIN dbo.v_Advertisement ON dbo.v_Collection.CollectionID = dbo.v_Advertisement.CollectionID "
$memberQuery += "WHERE (LOWER(dbo.v_FullCollectionMembership.Name) = LOWER('$srv'))"
and the $sObject variable to:-
$sObject = $enumColl | select Hostname, ResourceID, "Collection Name", CollectionID, IsDirect, AdvertisementID, AdvertisementName
Complete script to view client collections with live advisements (execution the same as before):-
[CmdletBinding()]
param (
[string] $hosts = "",
[string] $sccmsrv = "",
[Parameter(Mandatory=$False,Position=3)]
[string] $path = ""
)
$usage = "USAGE: List-AdvertCollMembershipSCCM.ps1 -sccmsrv SCCMSERVER -hosts 'host1 host2 host3' -path 'c:\temp\Outfile.csv'"
if ($host -and $sccmsrv){
Write-Host ""
Write-Host -ForegroundColor Yellow "SCCM Server: $sccmsrv"
Write-Host -ForegroundColor Yellow "Looking at hosts: $hosts"
#### Function for executing a SQL query with integrated authentication
function execSQLQuery ([string]$fSQLServer, [string]$db, [string]$query){
$objConnection = New-Object System.Data.SqlClient.SqlConnection
$objConnection.ConnectionString = "Server = $fSQLServer; Database = $db; trusted_connection=true;"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand $query, $objConnection
trap {Write-Host -ForegroundColor 'red' "($sqlsrv/$db not accessible)";continue}
$SqlCmd.Connection.Open()
if ($SqlCmd.Connection.State -ine 'Open') {
$SqlCmd.Connection.Close()
return
}
$dr = $SqlCmd.ExecuteReader()
#get the data
$dt = new-object "System.Data.DataTable"
$dt.Load($dr)
$SqlCmd.Connection.Close()
$dr.Close()
$dr.Dispose()
$objConnection.Close()
return $dt
}
# read the SCCM site name of the SCCM site server
$site = (gwmi -ComputerName $sccmsrv -Namespace root\sms -Class SMS_ProviderLocation).sitecode
# enumerating SQL server name for the given SCCM site server
$sccmCompquery = gwmi -q "Select distinct SiteSystem, Role, SiteCode FROM SMS_SiteSystemSummarizer where role = 'SMS SQL Server' and siteCode = '$site' ORDER BY SiteCode" -namespace "root\sms\site_$site" -ComputerName $sccmsrv
[string]$tmpstr = [regex]::Match($sccmCompquery.sitesystem, "\\\\\w+\\$")
$sccmSQLServer = $tmpstr.replace("\", "")
$objColl = #()
#### Collate the host list.
$hostlist = #($Input)
if ($hosts) {
if($hosts -imatch " "){
$hostsArr = #($hosts.split(" "))
$hostlist += $hostsArr
}
else{
$hostlist += $hosts
}
}
# going through the list of hosts
foreach($srv in $hostlist){
$memberQuery = "SELECT dbo.v_FullCollectionMembership.Name AS 'Hostname', dbo.v_GS_SYSTEM.ResourceID, dbo.v_Collection.Name AS 'Collection Name',dbo.v_Collection.CollectionID, dbo.v_FullCollectionMembership.IsDirect, dbo.v_Advertisement.AdvertisementID, dbo.v_Advertisement.AdvertisementName "
$memberQuery += "FROM dbo.v_FullCollectionMembership INNER JOIN dbo.v_Collection ON dbo.v_FullCollectionMembership.CollectionID = dbo.v_Collection.CollectionID INNER JOIN dbo.v_GS_SYSTEM ON dbo.v_FullCollectionMembership.ResourceID = dbo.v_GS_SYSTEM.ResourceID INNER JOIN dbo.v_Advertisement ON dbo.v_Collection.CollectionID = dbo.v_Advertisement.CollectionID "
$memberQuery += "WHERE (LOWER(dbo.v_FullCollectionMembership.Name) = LOWER('$srv'))"
# running sql query to enumerate list of collections the computer is member of
$membership = execSQLQuery $sccmSQLServer "SMS_$site" $memberQuery
# if we have a result, go through it and build an object collection with the computer name and the collection(s) it is member of
if($membership){
foreach($enumColl in $membership){
$sObject = $enumColl | select Hostname, ResourceID, "Collection Name", CollectionID, IsDirect, AdvertisementID, AdvertisementName
$objColl +=$sObject
}
}
}
if ($objColl){
if ($path){
$objColl | ft -AutoSize
Write-Host -ForegroundColor Yellow "Exporting to results to: $path"
$objColl | Export-Csv $path -NoTypeInformation
}
else{
$objColl | ft -AutoSize
Write-Host -ForegroundColor Green "Use the -path argument in the command line to export output to csv to display"
Write-Host -ForegroundColor Green "the header 'AdvertisementName'"
Write-Host ""
}
}
Else {
foreach ($Hostname in $hostlist){
Write-Host ""
Write-Host -ForegroundColor Yellow "The host $hostname is not a member of any collection with live advertisements"
}
Write-Host -ForegroundColor Yellow "Check you have entered the correct hostname and try again"
}
}
else {
Write-Host ""
Write-Host -ForegroundColor Yellow $usage
}
And if you connect to SCCM from station with only SCCM Console installed and every other SCCM cmdlets works, trying Get-WmiObject:
Get-WmiObject -Namespace "root\sms\site_$SiteCode" ...
you will have an error:
“Get-WmiObject : Invalid namespace …”
In this situation you should specify parameter ComputerName and point to server where SCCM is installed:
Get-WmiObject -ComputerName "SCCMserver" -Namespace "root\sms\site_$SiteCode" ...
Hope it helps, I waste few minutes by this.