The term 'xWebsite' is not recognized as the name of a cmdlet - powershell

I installed xWebAdministration module. For some reason I am still getting this error message
The term 'xWebsite' is not recognized as the name of a cmdlet"
image url: http://i.stack.imgur.com/tTwUe.jpg
here's my code.
Configuration MvcWebTest {
Param(
[String[]]$ComputerName = "tvw-irwebsvc",
$AppName = "MvcWebTest",
$User = "PAOMSvc",
$Password = "Welcome1",
$CodePath = "C:\websites\MvcWebTest"
)
Import-DscResource -Module xWebAdministration
Node $ComputerName {
#Install ASP.NET 4.5
WindowsFeature ASP {
Ensure = “Present”
Name = “Web-Asp-Net45”
}
File WebContent {
Ensure ="Present";
SourcePath ="\\DVW-MORBAM01\Build\Publish\MvcWebTest\Dev";
DestinationPath=$CodePath;
Type = "Directory";
Recurse = $True
}
# Create a new website
xWebsite Website {
Ensure = "Present";
Name = $AppName;
State = "Started";
PhysicalPath = $CodePath;
DependsOn = "[File]WebContent"
}
}
}

The screenshot is showing you the problem: The xWebsite resource isn't installed. Only the xwebApplication and xWebVirtualDirectory resources are installed.
I just downloaded the xWebAdministration 1.3.2.3 zip file from Technet, and it looks like someone made a boo-boo -- it's missing xWebSite! The Q&A section is full of people upset about it, so you're not alone. :)
Oddly enough, the Wave 9 resource kit that supposedly includes all the modules has the same problem!
The easiest way to get past this is to just grab version 1.3.2, which looks like it has everything.

To enact the configuration, run the following command:
Start-DscConfiguration -Wait -Verbose -Path .\MvcWebTest
This cmdlet is part of the DSC system. The Wait parameter is optional and makes the cmdlet run interactively. Without this parameter, the cmdlet will create and return a job.

Related

Powershell - How to script a session refresh in powershell?

I have one ps1 script that drives the operations I want to perform.
I am using modules with class definitions in the modules that use Command pattern.
All is well and good first time I open a powershell session console and run the script.
If I change a class in any way and re-run in the same console, the console does not seem to be picking up the changed script. I have to close the powershell console and run the script fresh in order for my changes work. Otherwise I just get the script behaving the same way it does before I made the change. Clearly there is some caching going on.
I am wondering if MS has finally resolved this issue. I have read many older posts with complaints about this.
I have tried the following and none of them appears to work:
Remove-Variable * -ErrorAction SilentlyContinue;
Remove-Module *;
$error.Clear();
Clear-Host
I have even tried all of them together. Still not helping.
Is there something else can can be done to ensure the latest code in any supporting modules gets loaded? Having to close the whole console and reload is a serious productivity issue.
Example of what I am doing:6
using module .\Logger.psm1
using module .\AzurePlatformParmsDefault.psm1
using module .\AzurePlatform.psm1
[Logger] $Logger = [Logger]::Create()
[AzurePlatformParms] $AzurePlatformParms = [AzurePlatformParmsDefault]::Create( $Logger )
[AzurePlatform] $AzurePlatform = [AzurePlatform]::Create( $Logger, $AzurePlatformParms )
[bool] $Result = $AzurePlatform.Execute()
The conventional wisdom is that there isn't a way to do this natively, and creating a new runspace or process is the solution.
You can reset variables to default values and import environment variables from the user/machine scope (on windows); before clearing any jobs, events, event subscribers etc. This isn't a true session refresh though, and classes/custom types will persist.
To speed up your workflow, you may want to use a function in your $profile that can automate creating a new session, and loading in what's needed. This approach can save enough time that it is trivial to recycle an interactive session. I will include the one I use in my profile as an example. It's fairly comprehensive, but I suggest tailoring one that is suitable for your specific needs.
Example
function Start-NewSession {
[CmdletBinding(DefaultParameterSetName = 'NoChange')]
[Alias('sans')]
param(
[Alias('N')]
[switch]
$NoClose,
[Parameter(ParameterSetName = 'Elevate')]
[Parameter(ParameterSetName = 'NoChange')]
[Alias('nop')]
[switch]
$NoProfile,
[Parameter(ParameterSetName = 'Elevate')]
[Parameter(ParameterSetName = 'NoChange')]
[Alias('A')]
[switch]
$AddCommands,
[Parameter(ParameterSetName = 'Elevate')]
[Alias('E')]
[switch]
$Elevate,
[Parameter(ParameterSetName = 'DeElevate')]
[Alias('D')]
[switch]
$DeElevate
)
$PSAppPath = (Get-Process -Id $PID).Path
$SPParams = #{
Filepath = $PSAppPath
WorkingDirectory = $PWD
ArgumentList = ''
}
if ($Elevate.IsPresent) {
$SPParams['Verb'] = 'RunAs'
}
elseif ($DeElevate.IsPresent) {
$SPParams['FilePath'] = Join-Path $env:windir 'explorer.exe'
$SPParams['ArgumentList'] = $PSAppPath
}
if ($NoProfile.IsPresent) {
$SPParams['ArgumentList'] += ' -NoProfile'
}
if ($AddCommands.IsPresent) {
$ExtraCmds = Read-Host -Prompt 'Post-startup commands'
if (-not [string]::IsNullOrWhiteSpace($ExtraCmds)) {
$SPParams['ArgumentList'] +=
' -NoExit -Command "' + $ExtraCmds.Replace('"', '\"') + '"'
}
}
if ([string]::IsNullOrWhiteSpace($SPParams['ArgumentList'])) {
$SPParams.Remove('ArgumentList')
}
Start-Process #SPParams
if (-not $NoClose.IsPresent) { exit }
}
This permits typing sans to generate a new session and close the old one.

Converting .ps1 file to a Windows Service

I'm trying to convert a .ps1 file to run as a windows service. This needs to run as a service as it's requirements for Business Continuity (scheduled task is not an option). i've always used NSSM to wrap the .ps1 as it will then run via NSSM as an exe.
This works for different scripts in Windows Server 2012, but this script is slightly different and i'm required to get this service to work on Windows Server 2016. The script itself, connects to a large amount of other servers (in total i'll have 3 services - Windows Service / Windows Process / Linux Process) which all work when just running within PowerShell.
Below is an example of the start of the script so you get an idea how it works (may not be relevant);
while ($test = 1)
{
[string]$query
[string]$dbServer = "DBSERVER" # DB Server (either IP or hostname)
[string]$dbName = "DBNAME" # Name of the database
[string]$dbUser = "CONNECTIONUSER" # User we'll use to connect to the database/server
[string]$dbPass = "CONNECTIONPASSWORD" # Password for the $dbUser
$conn = New-Object System.Data.Odbc.OdbcConnection
$conn.ConnectionString = "Driver={PostgreSQL Unicode(x64)};Server=$dbServer;Port=5432;Database=$dbName;Uid=$dbUser;Pwd=$dbPass;"
$conn.open()
$cmd = New-object System.Data.Odbc.OdbcCommand("select * from DBNAME.TABLENAME where typeofcheck = 'Windows Service' and active = 'Yes'",$conn)
$ds = New-Object system.Data.DataSet
(New-Object system.Data.odbc.odbcDataAdapter($cmd)).fill($ds) | out-null
$conn.close()
$results = $ds.Tables[0]
$Output = #()
foreach ($result in $results)
{
$Hostone = $Result.hostone
$Hosttwo = $Result.hosttwo
$Hostthree = $Result.hostthree
$Hostfour = $Result.hostfour
Write-Output "checking DB ID $($result.id)"
#Host One Check
if (!$result.hostone)
{
$hostonestatus = 17
$result.hostone = ""
}
else
{
try
{
if(Test-Connection -ComputerName $result.hostone -quiet -count 1)
{
$hostoneres = GET-SERVICE -COMPUTERNAME $result.hostone -NAME $result.ServiceName -ErrorAction Stop
$hostonestatus = $hostoneres.status.value__
$Result.HostOneCheckTime = "Last checked from $env:COMPUTERNAME at $(Get-date)"
}
else
{
$hostonestatus = 0
$result.hostonestatus = "Failed"
$Result.HostOneCheckTime = "Last checked from $env:COMPUTERNAME at $(Get-date)"
}
}
catch
{
$hostonestatus = 0
$result.hostonestatus = "Failed"
$Result.HostOneCheckTime = "Last checked from $env:COMPUTERNAME at $(Get-date) Errors Found"
}
if ($hostonestatus -eq 4)
{
$result.hostonestatus = "Running"
}
if ($hostonestatus -eq 1)
{
$result.hostonestatus = "Stopped"
}
elseif ($hostonestatus -eq 0)
{
$result.hostonestatus = "Failed"
}
}
As mentioned, the exact script running standalone works seamlessly.
Whats the best way to run this as a service or are there any known issues with NSSM when using it with Windows Server 2016?
I've also found the below which may be pointing in the right direction as i've intermittently got these in the logs;
DCOM event ID 10016 is logged in Windows
Windows sysadmin here.
Quiet a few different ways to accomplish this from a purely service-orientated perspective.
--- 1 ---
If you are using Server 2016, I believe that the Powershell command 'New-Service' may be one of the cleanest ways. Have a look at the following for syntax and if it suits your use case --
https://support.microsoft.com/en-au/help/137890/how-to-create-a-user-defined-service
This CMDlet takes a credential parameter, so depending on your use case may be good to access resources on other foreign machines.
--- 2 ---
Another way is to use the old trusty in-built SC.exe utility in windows.
SC CREATE <servicename> Displayname= "<servicename>" binpath= "srvstart.exe <servicename> -c <path to srvstart config file>" start= <starttype>
An example --
SC CREATE Plex Displayname= "Plex" binpath= "srvstart.exe Plex -c C:PlexService.ini" start= auto
As far as I can tell, this will create a service that will execute under the Local System context. For more information, have a look at the following:
https://support.microsoft.com/en-au/help/251192/how-to-create-a-windows-service-by-using-sc-exe
https://www.howtogeek.com/50786/using-srvstart-to-run-any-application-as-a-windows-service/
--- 3 ---
You may want to consider manually injecting some registry keys to create your own service (which is essentially what SC.exe does under the hood).
Although I'm unfortunately in no position at the moment to provide boiler-plate code, I'd encourage that you have a look at the following resource:
https://www.osronline.com/article.cfm%5Eid=170.htm
NOTE - you will need to provide all required sub-keys for it to work.
As with any registry changes, please make a backup of your registry and perform edits at your own risk prior to making any changes. I can only recommend to try this on a spare/test VM if possible prior to implementing to prod.

How to register the result of a PowerShell expression in a variable for a DSC?

I am trying to configure an Azure VM with Azure Automation DSC. One of the resources I want to set is DNS on the client workstation with xDnsServerAddress from xNetworking module.
The problem is that it requires an interface alias and interface aliases change on Azure VMs vary depending on deployment (mainly VMs seem to get either Ethernet or Ethernet 2).
I can query the interface name locally using the following cmdlet expression:
$Interface=Get-NetAdapter|Where Name -Like "Ethernet*"|Select-Object -First 1
$InterfaceAlias=$($Interface.Name)
I don't know, however, how to use it inside the DSC.
My DSC configuration is as below (only the relevant part):
Configuration MyDscConfig
{
Import-DscResource -ModuleName xNetworking
# place-1
Node $AllNodes.where{$_.Role -eq "Workstation"}.NodeName
{
# place-2
xDnsServerAddress DnsServerAddressSetToDc1
{
Address = '10.0.0.4'
InterfaceAlias = $InterfaceAlias
AddressFamily = 'IPv4'
Validate = $true
}
}
}
The problem is that if I place the cmdlet expression either in place-1 or place-2 the compilation job fails with:
The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: The term 'Get-NetAdapter' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
I assume it tries to execute Get-NetAdapter on the pull server, but I may be misinterpreting the error message.
How can I register the result of the cmdlet expression on a destination machine and register it in $InterfaceAlias variable for the xDnsServerAddress resource?
You currently cannot perform a query keep the results of the operation and use it to declare the next state (See notes at the end of the answer.)
You can work around this limitation using the documented workaround/solution from xNetworking, which will find an active ethernet adapter named Ethernet1 if it does not, it will find the first active ethernet adapter and make sure it is named Ethernet1. Then, use a resource to set the DSC server address on Ethernet1.
This is investigational, names and parameters are subject to change. The DSC team is investigating a better way to do this.
Configuration SetDns
{
param
(
[string[]]$NodeName = 'localhost'
)
Import-DSCResource -ModuleName xNetworking
Node $NodeName
{
script NetAdapterName
{
GetScript = {
Import-module xNetworking
$getResult = Get-xNetworkAdapterName -Name 'Ethernet1'
return #{
result = $getResult
}
}
TestScript = {
Import-module xNetworking
Test-xNetworkAdapterName -Name 'Ethernet1'
}
SetScript = {
Import-module xNetworking
Set-xNetworkAdapterName -Name 'Ethernet1' -IgnoreMultipleMatchingAdapters
}
}
xDnsServerAddress DnsServerAddress
{
Address = '10.0.0.4'
InterfaceAlias = 'Ethernet1'
AddressFamily = 'IPv4'
DependsOn = #('[Script]NetAdapterName')
}
}
}
Notes:
There is a question in the comments. The summary of the question is if querying turns the declarative paradigm into an imperative paradigm.
Answer:
I don't believe querying turns it into an imperative paradigm, but you
currently cannot perform a query keep the results of the operation and
use it to declare the next state.
This currently forces us into something a little further away from
declarative for the problem that I would like. My personal opinion is that we
should work with what we have and write resources that query and set a
known state. Then, use the known state through the rest of the
configuration (a form a declarative-relative, per your terminology).
The DSC team has this similar UserVoice
suggestion
we are using to track this request. Please upvote it if you think this
is a useful feature.
It seems the DSC Node Configuration (which is a MOF file) must have all the values set at the time of compilation.
As a workaround I decided to use a PowerShell script resource instead of xDnsServerAddress (some values below are hardcoded to match the example in the question):
Script DnsServerAddressSetToDc1
{
GetScript = {
Return #{
Result = [string](get-DnsClientServerAddress -InterfaceAlias (Get-NetAdapter|Where Name -Like "Ethernet*"|Select-Object -First 1).Name -AddressFamily IPv4).ServerAddresses
}
}
TestScript = {
if (([string](get-DnsClientServerAddress -InterfaceAlias (Get-NetAdapter|Where Name -Like "Ethernet*"|Select-Object -First 1).Name -AddressFamily IPv4).ServerAddresses) -eq '10.0.0.4') {
Write-Verbose "DNS server set"
Return $true
} Else {
Write-Verbose "DNS Server not set"
Return $false
}
}
SetScript = {
Set-DnsClientServerAddress `
-InterfaceAlias (Get-NetAdapter|Where Name -Like "Ethernet*"|Select-Object -First 1).Name `
-ServerAddresses 10.0.0.4 `
-Validate `
-ErrorAction Stop
}
}

PowerShell DSC - how to pass configuration parameters to ScriptResources?

I'm having a lot of trouble trying to get a PowerShell Desired State Configuration script working to configure an in-house application. The root of the problem is that I can't seem to pass my configuration data down into a ScriptResource (at least not with the way I'm trying to do it).
My script is supposed to create a config folder for our in-house application, and then write some settings into a file:
configuration MyApp {
param (
[string[]] $ComputerName = $env:ComputerName
)
node $ComputerName {
File ConfigurationFolder {
Type = "Directory"
DestinationPath = $Node.ConfigFolder
Ensure = "Present"
}
Script ConfigurationFile {
SetScript = {
write-verbose "running ConfigurationFile.SetScript";
write-verbose "folder = $($Node.ConfigFolder)";
write-verbose "filename = $($Node.ConfigFile)";
[System.IO.File]::WriteAllText($Node.ConfigFile, "enabled=" + $Node.Enabled);
}
TestScript = {
write-verbose "running ConfigurationFile.TestScript";
write-verbose "folder = $($Node.ConfigFolder)";
write-verbose "filename = $($Node.ConfigFile)";
return (Test-Path $Node.ConfigFile);
}
GetScript = { #{Configured = (Test-Path $Node.ConfigFile)} }
DependsOn = "[File]ConfigurationFolder"
}
}
}
For reference, my configuration data looks like this:
$config = #{
AllNodes = #(
#{
NodeName = "*"
ConfigFolder = "C:\myapp\config"
ConfigFile = "C:\myapp\config\config.txt"
}
#{
NodeName = "ServerA"
Enabled = "true"
}
#{
NodeName = "ServerB"
Enabled = "false"
}
)
}
And I'm applying DSC with the following:
$mof = MyApp -ConfigurationData $config;
Start-DscConfiguration MyApp –Wait –Verbose;
When I apply this configuration it happily creates the folder, but fails to do anything with the config file. Looking at the output below, it's obvious that it's because the $Node variable is null inside the scope of ConfigurationFile / TestScript, but I've got no idea how to reference it from within that block.
LCM: [ Start Resource ] [[Script]ConfigurationFile]
LCM: [ Start Test ] [[Script]ConfigurationFile]
[[Script]ConfigurationFile] running ConfigurationFile.TestScript
[[Script]ConfigurationFile] node is null = True
[[Script]ConfigurationFile] folder =
[[Script]ConfigurationFile] filename =
LCM: [ End Test ] [[Script]ConfigurationFile] in 0.4850 seconds.
I've burnt off an entire day searching online for this specific problem, but all the examples of variables, parameters and configuration data all use File and Registry resources or other non-script resources, which I've already got working in the "ConfigurationFolder" block in my script. The thing I'm stuck on is how to reference the configuration data from within a Script resource like my "ConfigurationFile".
I've drawn a complete blank so any help would be greatly appreciated. If all else fails I may have to create a separate "configuration" script per server and hard-code the values, which I really don't want to do if at all possible.
Cheers,
Mike
Change this: $Node.ConfigFolder to $using:Node.ConfigFolder.
If you have a variable called $Foo and you want it to be passed to a script DSC resource, then use $using:Foo
Based on David's answer, I've written a utility function which converts my script block to a string and then performs a very naive search and replace to expand out references to the configuration data as follows.
function Format-DscScriptBlock()
{
param(
[parameter(Mandatory=$true)]
[System.Collections.Hashtable] $node,
[parameter(Mandatory=$true)]
[System.Management.Automation.ScriptBlock] $scriptBlock
)
$result = $scriptBlock.ToString();
foreach( $key in $node.Keys )
{
$result = $result.Replace("`$Node.$key", $node[$key]);
}
return $result;
}
My SetScript then becomes:
SetScript = Format-DscScriptBlock -Node $Node -ScriptBlock {
write-verbose "running ConfigurationFile.SetScript";
write-verbose "folder = $Node.ConfigFolder";
write-verbose "filename = $Node.ConfigFile)";
[System.IO.File]::WriteAllText("$Node.ConfigFile", "enabled=" + $Node.Enabled);
}
You have to be mindful of quotes and escapes in your configuration data because Format-DscScriptBlock only performs literal substitution, but this was good enough for my purposes.
A quite elegant way to solve this problem is to work with the regular {0} placeholders. By applying the -f operator the placeholders can be replaced with their actual values.
The only downside with this method is that you cannot use the curly braces { } for anything other than placeholders (i.e. say a hashtable or a for-loop), because the -f operator requires the braces to contain an integer.
Your code then looks like this:
SetScript = ({
Set-ItemProperty "IIS:\AppPools\{0}" "managedRuntimeVersion" "v4.0"
Set-ItemProperty "IIS:\AppPools\{0}" "managedPipelineMode" 1 # 0 = Integrated, 1 = Classic
} -f #($ApplicationPoolName))
Also, a good way to find out if you're doing it right is by simply viewing the generated .mof file with a text editor; if you look at the generated TestScript / GetScript / SetScript members, you'll see that the code fragment really is a string. The $placeholder values should already have been replaced there.
ConfigurationData only exists at the time the MOF files are compiled, not at runtime when the DSC engine applies your scripts. The SetScript, GetScript, and TestScript attributes of the Script resource are actually strings, not script blocks.
It's possible to generate those script strings (with all of the required data from your ConfigurationData already expanded), but you have to be careful to use escapes, subexpressions and quotation marks correctly.
I posted a brief example of this over on the original TechNet thread at http://social.technet.microsoft.com/Forums/en-US/2eb97d67-f1fb-4857-8840-de9c4cb9cae0/dsc-configuration-data-for-script-resources?forum=winserverpowershell

Powershell DSC: Can someone please provide me an example on how to use a resource?

To the DSC pros, this may seem like a very simple question but I couldn't find any resources on the web for this, or for any of the error messages I've seen. It seems very difficult to dig up any information on DSC so perhaps we can start here.
I am trying to build a Powershell DSC configuration for installing a scheduled task. I have found a sample resource on Steve Murawski's Github page for StackExchange resources, and I have copied the 'StackExchangeResources' tree to my DSC repository.
I imported the StackExchangeModule and attempted to create a very simple configuration using the ScheduledTask resource:
Import-Module StackExchangeResources
Configuration TempCleaner
{
param($NodeName)
Node $NodeName
{
$filePath = "C:\Tasks\TempCleaner.ps1";
ScheduledTask
{
Name = "Clear Temporary Files"
FilePath = $filePath
Daily = $true
FilePath = ""
Hours = 4
Minutes = 0
}
}
}
However, when I execute TempCleaner -Node TestNode, it doesn't actually do anything; no MOF files are written and no errors are thrown.
Now, a lot of examples I've seen involve giving a name to the invocation of the resource, something like this:
File TempCleaner
{
DestinationPath = $filePath
Contents = $(cat $tempCleanerScript | out-string)
Checksum = "SHA-512"
}
But when I try to give it a name like so,
ScheduledTask CleanerTask
{
Name = "Clear Temporary Files"
FilePath = $filePath
Daily = $true
FilePath = ""
Hours = 4
Minutes = 0
}
it will throw an exception:
ScheduledTask : No MSFT_ScheduledTask objects found with property 'TaskName' equal to
'CleanerTask'. Verify the value of the property and retry.
At C:\Users\Steve\Documents\DevOps\DSC\TempCleaner.ps1:13 char:9
+ ScheduledTask CleanerTask
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (CleanerTask:String) [Get-ScheduledTask]
, CimJobException
+ FullyQualifiedErrorId : CmdletizationQuery_NotFound_TaskName,Get-ScheduledTask
When I use the scheduled task resource in conjunction with the file resource as shown above, the file resource is written into the resulting MOF file but no other directives can be seen within.
There must be something I'm missing here. Is there some sort of verbose mode I can enable perhaps? Other logging options that aren't documented? That would be very helpful.
1) To use third party resource, you need to import it using Import-DscResource, not Import-Module.
Import-DscResource -Name StackExchange_ScheduledTask -ModuleName
StackExchangeResources
Also, note that it has to be in the Configuration scope
2) Make sure the resource module you are using is deployed to C:\Program Files\WindowsPowerShell\Modules\
Place whole StackExchangeResources folder with it's contents (DSCResources etc.) there.
3) Resource name is mandatory
ScheduledTask task
{
#...
}
here's the configuration with fixes:
Configuration TempCleaner
{
param($NodeName)
Import-DscResource -Name StackExchange_ScheduledTask -ModuleName StackExchangeResources
Node $NodeName
{
$filePath = "C:\test\TempCleaner.ps1";
ScheduledTask task
{
Name = "Clear Temporary Files"
FilePath = $filePath
Daily = $true
Hours = 4
Minutes = 0
}
}
}
Hope it helps.
If you are looking for an introduction to DSC, then I would suggest starting at:
PowerShell MVP Aman Dhally's blog.
PowerShell MVP Ravikanth C's post on PowerShellMagazine
Can't add comments yet, so editing my response. I think you may have duplicate keys in our resource.
Import-Module StackExchangeResources
Configuration TempCleaner
{
param($NodeName)
Node $NodeName
{
$filePath = "C:\Tasks\TempCleaner.ps1";
ScheduledTask
{
Name = "Clear Temporary Files"
FilePath = $filePath
Daily = $true
#FilePath = "" - Need unique keys. Also, FilePath is only a string not string[]
Hours = 4
Minutes = 0
}
}
}