DSC for initialising and formatting disks - powershell

I need to format a disk for servers using DSC. I tried using the below from
https://blogs.msdn.microsoft.com/timomta/2016/04/23/how-to-use-powershell-dsc-to-prepare-a-data-drive-on-an-azure-vm/#comment-1865
But it doesnt work as it doesn't seem to be complete, I get errors
"+ xWaitforDisk Disk2 + ~~~~~~~~~~~~ Resource 'xWaitForDisk' requires
that a value of type 'String' be provided for property 'DiskId'.
At line:18 char:1 + DiskNumber = 2 + ~~~~~~~~~~ The member
'DiskNumber' is not valid. Valid members are 'DependsOn', 'DiskId',
'DiskIdType', 'PsDscRunAsCredential', 'RetryCount',
'RetryIntervalSec'. "
Configuration DataDisk
{
Import-DSCResource -ModuleName xStorage
Node localhost
{
xWaitforDisk Disk2
{
DiskNumber = 2
RetryIntervalSec = 60
Count = 60
}
xDisk FVolume
{
DiskNumber = 2
DriveLetter = 'F'
FSLabel = 'Data'
}
}

You need to replace DiskNumber with DiskID.
Take a look at the examples on GitHub https://github.com/PowerShell/StorageDsc/tree/dev/Modules/StorageDsc/Examples/Resources
You can find the DiskId with powershell use the command: Get-Disk

Related

PowerShell Unable to find type

I'm having trouble with an error when I try to run my PowerShell script from the command line:
Unable to find type [System.Windows.Forms.ListViewItem]
I have tried different ways to import the required classes:
using assembly System.Windows.Forms
using namespace System.Windows.Forms
using namespace System.Drawing
Add-Type System.Windows.Forms
In PowerShell ISE, I can run my script without any errors. But when I try to execute my script from CMD it doesn't work. It's exactly the same code and the same script files. This is the command I use to execute the script in CMD followed by the error messages:
C:\Users\Admin>powershell -File "C:\Folder\Main.ps1"
At C:\Folder\Main.ps1:35 char:30
+ ... return (([int](([System.Windows.Forms.ListViewItem]$a).Sub ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unable to find type [System.Windows.Forms.ListViewItem].
At C:\Folder\Main.ps1:35 char:114
+ ... umnIndex].Text)) - ([int](([System.Windows.Forms.ListViewItem]$b).Sub ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unable to find type [System.Windows.Forms.ListViewItem].
At C:\Folder\Main.ps1:37 char:41
+ ... return ([String]::Compare(([System.Windows.Forms.ListViewItem]$a).Sub ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unable to find type [System.Windows.Forms.ListViewItem].
At C:\Folder\Main.ps1:37 char:115
+ ... [$this.columnIndex].Text, ([System.Windows.Forms.ListViewItem]$b).Sub ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unable to find type [System.Windows.Forms.ListViewItem].
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : TypeNotFound
The error messages refer to the code below. This is my only class in that script:
class ListViewItemComparer : System.Collections.IComparer {
[int]$sortOrder
[String]$columnType
[int]$columnIndex
ListViewItemComparer() {
$this.sortOrder = 1
$this.columnType = "String"
$this.columnIndex = 0
}
ListViewItemComparer([int]$sortOrder, [String]$columnType, [int]$columnIndex) {
$this.sortOrder = $sortOrder
$this.columnType = $columnType
$this.columnIndex = $columnIndex
}
[void] ChangeSorting([int]$columnIndex, [String]$columnType) {
if($this.columnIndex -eq $columnIndex) {
$this.sortOrder *= -1
} else {
$this.columnIndex = $columnIndex
$this.sortOrder = 1
}
$this.columnType = $columnType
}
[int] Compare([Object]$a, [Object]$b) {
if($this.columnType -eq "Number") {
return (([int](([System.Windows.Forms.ListViewItem]$a).SubItems[$this.columnIndex].Text)) - ([int](([System.Windows.Forms.ListViewItem]$b).SubItems[$this.columnIndex].Text))) * $this.sortOrder
} else {
return ([String]::Compare(([System.Windows.Forms.ListViewItem]$a).SubItems[$this.columnIndex].Text, ([System.Windows.Forms.ListViewItem]$b).SubItems[$this.columnIndex].Text)) * $this.sortOrder
}
}
}
I'm using the type System.Windows.Forms.ListViewItem at other places too in my code, but there is no problem outside of a class. I don't even have to write the whole class path, just ``ListViewItem` works as well.
Can somebody tell me why the type System.Windows.Forms.ListViewItem is not recognized?
Why is it recognized outside the ListViewItemComparer class in the same script file?
Why does this error occur when I run the script from CMD and not in PowerShell ISE?

Windows Server 2016 Dockerfile install service

I am attempting to install a service in a docker container on windows server2016.
Simply placing the service there and Powershelling:
New-Service -Name Bob -StartupType Automatic -BinaryPathName .\SVCHost.exe
Adds the service however in the container I get the result:
PS C:\Program Files\COMPANY\Repository> start-service -Name bob
start-service : Service 'bob (Bob)' cannot be started due to the following error: Cannot start service Bob on computer '.'.
At line:1 char:1
+ start-service -Name bob
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (System.ServiceProcess.ServiceController:ServiceController) [Start-Service], ServiceCommandException
I have attempted creating a user and setting the startup user credentials but same issue.
Looking at https://github.com/Microsoft/sql-server-samples/blob/master/samples/manage/windows-containers/mssql-server-2016-express-windows/dockerfile shows that they use sqlexpress to do the install of the service.
Long story short...
How do I register a service in a Windows server 2016 Docker container
Also, look at the Dockerfile for microsoft/iis. The real work in the container is done in the IIS Windows Service, but the entrypoint is a binary called ServiceMonitor.exe. The monitor checks the Windows Service, if the Service fails the exe fails, so Docker knows the container is unhealthy.
Fully qualifying the install name works. thanks #Elton Stoneman
or figured out this works too in my program
public static bool Install(string serviceName, string serviceDescription, string logonUsername, string logonPassword, string exeFile)
{
string managementPath = #"\\.\ROOT\CIMV2:Win32_Service";
ManagementClass mc = new ManagementClass(managementPath);
ManagementBaseObject inParams = mc.GetMethodParameters("create");
inParams["Name"] = serviceName;
inParams["DisplayName"] = serviceDescription;
inParams["PathName"] = exeFile + " -name " + "\"" + serviceName + "\"";
inParams["ServiceType"] = ServiceType.Win32OwnProcess;
inParams["ErrorControl"] = 0;
inParams["StartMode"] = ServiceStartMode.Automatic;
inParams["DesktopInteract"] = false;
inParams["StartName"] = logonUsername;
inParams["StartPassword"] = logonPassword;
inParams["LoadOrderGroup"] = null;
inParams["LoadOrderGroupDependencies"] = null;
inParams["ServiceDependencies"] = null;
ManagementBaseObject outParams = mc.InvokeMethod("create", inParams, null);
string status = outParams["ReturnValue"].ToString();
return (status == "0" || status == "23");
}

Override Creation for Monitors and Rules

I want to create PowerShell scripts to override some parameter of my monitor and rule. I used the below code, but I have some errors. I want override my overidable parameter not enabled or something else. How can I doe this?
$mps = Get-SCOMManagementPack | ? {$_.Name -like "test"}
$overrideMp = Get-SCOMManagementPack -DisplayName "Overrides"
$overridename = "testmonitor.Overrides"
$monitor = 'testmonitor'
$override = New-Object Microsoft.EnterpriseManagement.Configuration.ManagementPackMonitorPropertyOverride($overrideMp,$overridename)
$override.Monitor = $monitor
$override.Property = 'WarningThreshold'
$override.Value = 80
$override.DisplayName = "Overrides"
$overrideMp.Verify()
$overrideMp.AcceptChanges()
Errors:
error1: Exception setting "Property": "Cannot convert value "WarningThreshold" to
type "Microsoft.EnterpriseManagement.Configuration.ManagementPackMonitorProperty".
Error: "Unable to match the identifier name WarningThreshold to a valid enumerator
name. Specify one of the following enumerator names and try again: Enabled,
TraceEnabled, Algorithm, AlgorithmPercentage, DefaultState, GenerateAlert,
AutoResolve, AlertPriority, AlertOnState, AlertSeverity, AlertMessage,
AlertParameter1, AlertParameter2, AlertParameter3, AlertParameter4,
AlertParameter5, AlertParameter6, AlertParameter7, AlertParameter8,
AlertParameter9, AlertParameter10, MemberInMaintenance, MemberUnavailable,
IgnoreMemberInMaintenance, IgnoreMemberUnavailable""
At line:1 char:2
+ $override.Property = $parametername
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
error2 : Exception calling "AcceptChanges" with "0" argument(s): "Database error.
MPInfra_p_ManagementPackInstall failed with exception: Failed to validate item:
testrule1"
At line:193 char:1
+ $MP.AcceptChanges()
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ManagementPackException
The error message looks rather clear to me. There is no property WarningThreshold in the ManagementPackMonitorProperty enumeration. I don't have much experience with SCOM, but you probably need to override the property AlertOnState for monitors where the property AlertSeverity has the value Warning.
Try something along the lines of this:
$mps | Get-SCOMMonitor | Where-Object {
# (other selection criteria) -and
$_.AlertSettings.AlertSeverity -eq 'Warning'
} | ForEach-Object {
$ctx = Get-SCOMClass -Id $_.Target.Id
# ...
$override = New-Object ...
$override.Monitor = $_
$override.Property = 'AlertOnState'
$override.Value = 80
$override.Context = $ctx
# ...
}
Code adopted from here (probably the same place where you found it). Not sure if this works, though. Like I said, I have very little experience with SCOM, and I don't have a SCOM server available for testing.
I'll try to debug it tomorrow in the office.
BTW, there is a third-party tool for override management called MPTuner: http://mpwiki.viacode.com/default.aspx?g=mptuner
It's free so you should try.
Roman.
It's quite confusing, but there are two different type of overrides for each workflow type. For a monitor there are:
MonitorPropertyOverride
MonitorConfigurationOverride
You are using the first one, wgich is for standard parameters only, like Enabled, for example. For any custom parameters use Configuration Override.

Ability to set CertificateID for LCM with February powershell 5

I'm trying to update my DSC deployment to now use partial configurations to break up the configuration. For that I need to now use a pull process instead of push.
When I try to apply the configuration for the LCM which looks something like:
[DscLocalConfigurationManager()]
Configuration CreateGESService
{
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullorEmpty()]
[PsCredential] $InstallCredential,
[Parameter(Mandatory=$true)]
[ValidateNotNullorEmpty()]
[PsCredential] $RunCredential
)
Node $AllNodes.NodeName
{
$hostVersion = (get-host).Version
# changed how the possible values for debugMode in the February build
if (($hostVersion.Major -ge 5) -and ($hostVersion.Minor -ge 0) -and ($hostVersion.Build -ge 9842)){
$debugMode = 'All'
}
else{
$debugMode = $true
}
#setup the localConfigManager
Settings
{
#CertificateID = $node.Thumbprint
# slower performance - and only available WMF5
# now we need to kill the dsc
DebugMode = $debugMode
ConfigurationMode = 'ApplyAndAutoCorrect'
ConfigurationModeFrequencyMins = '15'
AllowModuleOverwrite = $true
RefreshMode = 'Push'
ConfigurationID = $node.ConfigurationID
}
PartialConfiguration GetEventStoreConfiguration {
Description = "Contains the stuff for GetEventStore Being Installed"
ConfigurationSource = "[ConfigurationRepositoryShare]ConfigSource"
RefreshMode = "Pull"
}
PartialConfiguration ExternalIntegrationConfiguration{
Description = "Contains the stuff for External Integration"
ConfigurationSource = "[ConfigurationRepositoryShare]ConfigSource"
DependsOn = '[PartialConfiguration]GetEventStoreConfiguration'
RefreshMode = "Pull"
}
PartialConfiguration ServeGroupSpike{
Description = "Contains the stuff for External Integration"
ConfigurationSource = "[ConfigurationRepositoryShare]ConfigSource"
DependsOn = '[PartialConfiguration]ExternalIntegrationConfiguration'
RefreshMode = "Pull"
}
ConfigurationRepositoryShare ConfigSource{
SourcePath = "\\someServer\Shared\dscService\Configuration"
Credential = $InstallCredential
}
ResourceRepositoryShare ResourceSource{
SourcePath = "\\someServer\Shared\dscService\Resources"
Credential = $InstallCredential
}
}
If I try to include the CertificateID I get an error like:
The property CertificateID of metaconfiguration is not compatible with the current version 2.0.0 of the configuration
document. This property only works with version greater than or equal to 1.0.0 . In case the version is greater, then
the property MinimumCompatibleVersion should be set to atleast 1.0.0 . Set these properties in the
OMI_ConfigurationDocument instance in the document and try again.
+ CategoryInfo : InvalidArgument: (root/Microsoft/...gurationManager:String) [], CimException
+ FullyQualifiedErrorId : MI RESULT 4
+ PSComputerName : SGSpike-Main
Naturally when the Configuration is attempted to be applied it can't decrypt the credentials passed, and I get an error in the event view like:
Job {B37D5239-EDBA-11E4-80C2-00155D9ACA1F} :
WarningMessage An error occured while applying the partial configuration [PartialConfiguration]ExternalIntegrationConfiguration. The error message is :
The Local Configuration Manager is not configured with a certificate. Resource '[File]GpgProgram' in configuration 'ExternalIntegrationConfiguration' cannot be processed..
Any ideas how to do this? I had this working with the certificateID when I was using a single configuration in a push model.
Even in the April 2015 drop the problem still seems to exist. Further diagnosis shows that you can:
Not use partial configurations
Not use a certificate to encrypt credentials
Opened an issue on connect (with some more details) at https://connect.microsoft.com/PowerShell/Feedback/Details/1292678

PowerShell InvokeGet the directory property cannot be found

We needed to retrieve the information in active directory concerning 'Terminal Services'. For this I've created a function that works fine most of the time. However, with some users we have issues.
The code:
Function Get-ADTSProfile {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true,Position=0)]
[String] $DistinguishedName,
[parameter(Mandatory=$true,Position=1)]
[ValidateNotNullOrEmpty()]
[ValidateSet('UserProfile','AllowLogon','HomeDirectory','HomeDrive')]
[String]$Property
)
Begin {
$User = [ADSI]"LDAP://$DistinguishedName"
}
Process {
Switch ($Property) {
'AllowLogon' {if ($($User.psbase.InvokeGet('allowLogon')) -eq '1'){$True}else{$False}}
'HomeDirectory' {$User.psbase.InvokeGet('TerminalServicesHomeDirectory')}
'HomeDrive' {$User.psbase.InvokeGet('TerminalServicesHomeDrive')}
'UserProfile' {$User.psbase.InvokeGet('TerminalServicesProfilePath')}
}
}
}
The error:
Get-ADTSProfile -DistinguishedName 'CN=test\, test (Den Bosch) NLD,OU=Users,OU=Disabled,OU=NLD,OU=EU,DC=domain,DC=net' -Property 'UserProfile'
Exception calling "InvokeGet" with "1" argument(s): "The directory property cannot be fo
und in the cache.
"
At S:\Test\Brecht\Testie.ps1:84 char:38
+ 'UserProfile' {$User.psbase.InvokeGet('TerminalServicesPro ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodTargetInvocation
I can't really figure out why it works on some and not on all..
I've been working on a recent project that uses ADSI to set and read Terminal Services attributes. From my testing anytime you perform a "InvokeGet({TS Attribute})" a COM exception will be thrown with the message "The directory property cannot be found in cache"
This seems to occur only when the "userParameters" attribute is not set in AD. Maybe the attribute internally checks the ADSI cache for userParameters? So i'm thinking logically you could check the DirectoryEntry for userParameters first, then try and read the properties, or else set it to construct the blob
if ($user.Properties.Contains("userParameters"))
{
#Read the Property from ADSI
Write-Host $user.InvokeGet("TerminalServicesProfilePath")
} else {
#Set the property to construct the userParameter blob
$user.InvokeSet("TerminalServicesProfilePath", "\\somepath")
$user.CommitChanges()
}
Even if the userParameters attribute is not set, you can still perform an InvokeSet to have it constructed