Installing executables with Powershell DSC - powershell

I am trying to install Visual Studio 2013 using PowerShell DSC but I'm running into a few issues and hoping that you guys could clear it up for me. Is DSC capable for rebooting the node and then resuming an installation of VS? Does anyone know what this error means? "vs_ultimate.exe was installed, but the specified ProductId and/or Name does not match package details"
Does anyone have any more specific examples of trying to install .exe with this method?
How does someone find out the ProductID?
Does anyone know the exact syntax of the ReturnCode?
Any help would be great!

If you have a system where the software was already installed you can find the ProductID using:
Get-WmiObject -Class Win32_Product | fl Name,Version,InstallDate,InstallSource,PackageName,IdentifyingNumber
Example output:
Name : Dell OpenManage Systems Management Software (64-Bit)
Version : 7.3.0
InstallDate : 20131009
InstallSource : c:\Installs\OMSA\
PackageName : SysMgmtx64.msi
IdentifyingNumber : {7CB08DC5-EA02-4076-BA7D-AD7736A3DE71}
Name : Microsoft ASP.NET MVC 4 Runtime
Version : 4.0.40804.0
InstallDate : 20141111
InstallSource : C:\windows\TEMP\IXP000.TMP\
PackageName : AspNetMVC4.msi
IdentifyingNumber : {3FE312D5-B862-40CE-8E4E-A6D8ABF62736}
Where IdentifyingNumber is the GUID you should use in the package resource. Example for the above Dell software:
package OMSA
{
Name = 'Dell OpenManage Systems Management Software (64-Bit)'
...
ProductId = '7CB08DC5-EA02-4076-BA7D-AD7736A3DE71'
Arguments = ...
}

Quoting Heath Stewart's comment:
the ProductId is the ProductCode of the MSI, which you can get by
opening the MSI in Orca (part of the Windows SDK) or you can install
my module from http://psmsi.codeplex.com and get it like so:
get-msitable <yourmsi.msi> -table Property | where { $_.Property -eq "ProductCode" }

The error means you have a mismatch in the Name or the ProductId of your Package resource against the msi content.
Easiest way in my experience to find both value is to use the Carbon powershell module.
Install-Module Carbon
Then simply run from powershell console:
msi "[path to your msi]"
Note: msi is an alias for Get-Msi
Example:
PS C:\Users\gigi\Downloads> msi .\node-v6.10.0-x64.msi
ProductName ProductVersion Manufacturer ProductCode
----------- -------------- ------------ -----------
Node.js 6.10.0 Node.js Foundation 84f68739-3b44-4d36-abdb-2151a23c9c3d
Copy and paste ProductName and ProductCode to your DSC package configuration and you are done.

I wrote a PowerShell function to find the product information
Function Get-InstallerProductProperty
{
# Define parameters
Param($installerFilePath,
$PropertyName)
# Verify file exists
if((Test-Path -Path $installerFilePath) -eq $true)
{
$path = $installerFilePath
$comObjWI = New-Object -ComObject WindowsInstaller.Installer
$MSIDatabase = $comObjWI.GetType().InvokeMember("OpenDatabase","InvokeMethod",$Null,$comObjWI,#($Path,0))
$Query = "SELECT Value FROM Property WHERE Property = '$PropertyName'"
$results = $View = $MSIDatabase.GetType().InvokeMember("OpenView","InvokeMethod",$null,$MSIDatabase,($Query))
$View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null)
$Record = $View.GetType().InvokeMember("Fetch","InvokeMethod",$null,$View,$null)
$Value = $Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,1)
# Return the product id
return $Value.Replace("{", "").Replace("}", "")
}
}

Related

Export/Import Printer .DRS file with PowerShell

I have 30+ Windows 2012 r2 servers, each with 30+ Zebra printers installed.
I want to be able to use PowerShell import (and export) the human readable .DRS files that can be generated with the print management UI in both the Preferences and Default locations.
I have seen lots of mentions of this: RUNDLL32.EXE PRINTUI.DLL,PrintUIEntry for import/export settings, but the file is not particularly readable, does not conform with requirements to store .DRS files, and I can't seem to get it to import the settings anyway.
I have admin on these servers, I am open to using the reg. but my understanding is that Zebras do custom things in the Devmode key - so it is not just a simple reg dump and conversion
I can use Get-PrintConfiguration and Get-CimInstance but not seeing Darkness, Speed, etc. in these outputs
$printerName = "Zebra_1"
$compNameSource = $env:COMPUTERNAME
$Printer = Get-CimInstance -ClassName Win32_Printer -Filter "Name='$PrinterName'"
$somePrinterConfig = Get-PrintConfiguration -ComputerName $compNameSource -PrinterName $printerName
$Printer.PSObject.Properties | ForEach-Object {
$_.Name, $_.Value
}
$somePrinterConfig.PSObject.Properties | ForEach-Object {
$_.Name, $_.Value
}
output:
Name : Caption
Value : Zebra_1
CimType : String
Flags : Property, ReadOnly, NotModified
IsValueModified : False
Name : Description
Value :
CimType : String
Flags : Property, ReadOnly, NotModified, NullValue
....
.DRS file:
[FileInfo]
Type=Driver Configuration File
Printer Type=201
[Barcodes]
BarcodeNum=6
[BARFONT0]
Name=EAN 13
UseHeight=1
JoinMode=2
StripTrailingSpaces=1
Kind=0
ID=1
Height=160
Expansion=1
Ratio=16908546
Flags=6164
…
[Parameters]
PaperSize=256
FormName=U
PageWidth=508
PageHeight=254
HDPI=300
VDPI=300
Orientation=3
Quantity=1
Cutter=0
BatchCut=0
Darkness=26
Speed=2
…

Get-Package command includes xml string - Need to convert to PSObject

Need Windows Update Install Date from Get-Package SwidTagText object. The object is in XML format and everything I have tried to convert doesn't work.
I am trying to switch from WMI because its terribly slow to pull back results.
Tried the ConvertFrom-XML function. Also tried ConvertFrom-String
Get-Package -ProviderName msu | Select-Object *
PropertyOfSoftwareIdentity : PropertyOfSoftwareIdentity
FastPackageReference : Definition Update for Windows Defender Antivirus - KB2267602 (Definition 1.297.486.0)
ProviderName : msu
Source :
Status : Installed
SearchKey :
FullPath : ?
PackageFilename : ?
FromTrustedSource : False
Summary : Install this update to revise the definition files that are used to detect viruses, spyware, and other potentially
unwanted software. Once you have installed this item, it cannot be removed.
SwidTags : {Definition Update for Windows Defender Antivirus - KB2267602 (Definition 1.297.486.0)}
CanonicalId : msu:Definition Update for Windows Defender Antivirus - KB2267602 (Definition 1.297.486.0)
Metadata : {summary,SupportUrl,Date,ResultCode}
SwidTagText : <?xml version="1.0" encoding="utf-16" standalone="yes"?>
<SoftwareIdentity
name="Definition Update for Windows Defender Antivirus - KB2267602 (Definition 1.297.486.0)"
xmlns="http://standards.iso.org/iso/19770/-2/2015/schema.xsd">
<Meta
summary="Install this update to revise the definition files that are used to detect viruses, spyware, and other
potentially unwanted software. Once you have installed this item, it cannot be removed."
SupportUrl="https://go.microsoft.com/fwlink/?LinkId=52661"
Date="7/5/2019 6:17:09 PM"
ResultCode="2" />
</SoftwareIdentity>
Dependencies : {}
IsCorpus :
Name : Definition Update for Windows Defender Antivirus - KB2267602 (Definition 1.297.486.0)
Version :
If you're trying to get the raw dates out of the XML you could do something like this:
$xml = ((Get-Package -ProviderName msu) | Select-Object *).SwidTagText
foreach ($item in $xml)
{
$(
$(
[xml]$item | Select-Object "InnerXml"
).InnerXml | Select-Xml -XPath "//*[#Date]"
).Node.Date
}
This gives you each entry to work with like so:
PS C:\Users\Skuld> $xml[0]
<?xml version="1.0" encoding="utf-16" standalone="yes"?>
<SoftwareIdentity
name="Update for Windows Defender Antivirus antimalware platform - KB4052623
(Version 4.18.1906.3)" xmlns="http://standards.iso.org/iso/19770/-2/2015/schema.xsd">
<Meta
summary="This package will update Windows Defender Antivirus antimalware
platform’s components on the user machine."
SupportUrl="https://go.microsoft.com/fwlink/?linkid=862339"
Date="09/07/2019 10:46:52"
ResultCode="2" />
</SoftwareIdentity>
You then use Select-XML/XPath to pick out the specific date attribute.
My example will give just a list of all the dates, but you could tweak it if you need extra information along side it.
Your code worked and now I make a function that searches for specific items inside the SwidTagText
Truly, Powershell is magical
#Use as much detail as possible. Can't process Arrays yet....
#Example = Get-Package -name "Application Name" | Where-Object { $_.ProviderName -eq "Programs" } | fl *
#Example = Get-Package -name "Application Name" | Where-Object { $_.ProviderName -eq "msi" } | fl *
#Returns any variable from XML SwidTagText
function SwidTagText-XML-Variable ( [string] $PackageName , [string] $XMLName, [string] $PackageType )
{
$PackageObject = Get-Package -name $PackageName | Where-Object { $_.ProviderName -eq $PackageType }
$xml= $PackageObject.SwidTagText
foreach ($item in $xml)
{
$XMLValue = $(
$(
[xml]$item | Select-Object "InnerXml"
).InnerXml | Select-Xml -XPath "//*[#$XMLName]"
).Node.$XMLName
}
return $XMLValue
}
#Example of Ubisoft Program and check for UninstallString
SwidTagText-XML-Variable "*ubisoft*" "UninstallString" "Programs"
So the function will search for an XML item inside the SwidTagText. Parsing and getting XML items from this is so useful

Get-WmiObject : Invalid class "SoftwareLicensingProduct"

I'm new to powershell and am trying to write a program that will get the product key of numerous servers.
I am looping through the server names and trying to do the following code but am getting the error in the title
$LicenseInfo = Get-WmiObject -Class SoftwareLicensingProduct -ComputerName $target -Credential $cred | `
Where-Object { $_.PartialProductKey -and $_.ApplicationID -eq "55c92734-d682-4d71-983e-d6ec3f16059f" } | Select-Object PartialProductKey, Description, ProductKeyChannel, #{ N = "LicenseStatus"; E = { $lstat["$($_.LicenseStatus)"] } }
Any help would be appreciated
That error is very specific. Are you targeting machines that do not have this class available? As per learn.microsoft.com for SoftwareLicensingProduct:
Minimum supported client: Windows 7
Minimum supported server: Windows Server 2008 R2

In Powershell, how do I pass a variable to a command to be added to an array?

Rather amateur scripter here, trying to pass lists of computer names to a command so it'll cycle through them and give me just their name, OS and OS version.
$Lab01comps = Get-ADComputer -SearchBase 'OU=Lab01,DC=domain,DC=domain,DC=domain' -Filter '*' | Select -Exp Name | sort
$Lab02comps = Get-ADComputer -SearchBase 'OU=Lab02,DC=domain,DC=domainstate,DC=edu' -Filter '*' | Select -Exp Name | sort
#This first one is more focused on just using a computer name in position 1. Example below code.
function Get-OS {
[CmdletBinding(DefaultParameterSetName="Remote")]
Param(
[Parameter(Position=1,ParameterSetName="Local")]
[Parameter(Position=2,ParameterSetName="Remote")]
[string]$ComputerName,
[System.Management.Automation.PSCredential]$Credential,
[switch]$Raw
)
If (! $ComputerName) {
$ComputerName = $env:COMPUTERNAME
}
foreach ($comp in $ComputerName) {
Get-ADComputer $ComputerName -cred $cred -prop OperatingSystem,OperatingSystemVersion | select name,OperatingSystem,OperatingSystemVersion
}
}
#Example
PS C:\> Get-OS LAB01COMP1
Name OperatingSystem OperatingSystemVersion
---- --------------- ----------------------
LAB01COMP1 Windows 7 Enterprise 6.1 (7601)
#Attempt 2: This one works, but it requires adding to the $osq array before running just the command, with no parameters. Example below code.
$osq = #()
function Get-OS2 {
foreach ($ComputerName in $osq) {
Get-ADComputer $ComputerName -cred $cred -prop OperatingSystem,OperatingSystemVersion | select name,OperatingSystem,OperatingSystemVersion
}
}
#Example
PS C:\> $osq += $Lab01comps
PS C:\> $osq
LAB01COMP1
LAB01COMP2
LAB01COMP3
PS C:\> Get-OS2
Name OperatingSystem OperatingSystemVersion
---- --------------- ----------------------
LAB01COMP1 Windows 7 Enterprise 6.1 (7601)
LAB01COMP2 Windows 7 Enterprise 6.1 (7601)
LAB01COMP3 Windows 7 Enterprise 6.1 (7601)
I know that was probably a pretty big block of code to post here, but I wanted to show all of what I'm trying so far. What I would like to be able to do is something like this:
PS C:\> Get-OS $Lab01comps
Name OperatingSystem OperatingSystemVersion
---- --------------- ----------------------
LAB01COMP1 Windows 7 Enterprise 6.1 (7601)
LAB01COMP2 Windows 7 Enterprise 6.1 (7601)
LAB01COMP3 Windows 7 Enterprise 6.1 (7601)
I feel like there's something simple I'm missing, but my attempts and online help searches have been kinda fruitless. It's a simple thing, to feed the variables to an array before just running the command, but for both the code itself, and the pursuit of knowledge for me, I'd like to know if what I'm trying to do is possible.
Thank you!
As PetSerAl said adding the empty brackets to the string will work.
[string]$ComputerName becomes [string[]]$ComputerName
This allows for the data to be treated as an array, not just a string of characters. Look at the below as an example.
#Using just [String]
[string]$data = 'this','is','my','array'
$data[0]
This will output just the letter t, because it takes the first position which is the letter t.
However, we are working with an array, not just a string of letters. So when we add the empty brackets
[string[]]$data = 'this','is','my','array'
$data[0]
This now outputs the word 'this' because it is being treated as an array, and the first item in that array is "this".
It's also worth mentioning that your second script worked because you declared it as an array using = #()
Without that, it's just a string variable.
Hope this helps! I'm new to powershell as well but boy isn't it fun learning it?

How to set ID attribute in IIS web-sites through windows powershell command

I'm trying to set the ID attribute of web-site in IIS through PowerShell script.
Tried with below command:
Set-ItemProperty IIS:\Sites\SetIDColumn -Name ID -Value 11
But this didn't help. Could any one please guide.
Refereed Simple Configuration Changes to Web-Sites and Application Pools
Outside of a ServerManager context, most EXISTING site properties are read-only.
So while you can inspect them, you can use a ServerManager object to change them.
Powershell Example:
Change site with Id 5 to Id 7, then change site "Default Web Site" to Id 99
Import-Module WebAdministration
$sm = Get-IISServerManager
$site = $sm.Sites | ? { $_.Id -eq 5 }
$site.Id = 7
$sm.CommitChanges()
$site = $sm.Sites | ? { $_.Name -eq "Default Web Site" }
$site.Id = 99
$sm.CommitChanges()