Downloads:
450,454
Downloads of v 2.2.0:
2,450
Last Update:
12 May 2016
Package Maintainer(s):
Software Author(s):
- Aaron Jensen
Tags:
.net acl active-directory certificates com compression computer credential cryptography directory dsc dsc-resources encryption environment file-system firewall groups hosts-file http identity iis ini installers internet-explorer ip junctions msi msmq netsh networking ntfs operating-system os path performance-counters powershell principal privileges programs registry rsa scheduled-tasks security service shares sid smb ssl text trusted-host users wcf windows windows-features xml zip psmodule dscresources setup automation admin- Software Specific:
- Software Site
- Software License
- Package Specific:
- Package outdated?
- Package broken?
- Contact Maintainers
- Contact Site Admins
- Software Vendor?
- Report Abuse
- Download
carbon
This is not the latest version of carbon available.
- 1
- 2
- 3
2.2.0 | Updated: 12 May 2016
- Software Specific:
- Software Site
- Software License
- Package Specific:
- Package outdated?
- Package broken?
- Contact Maintainers
- Contact Site Admins
- Software Vendor?
- Report Abuse
- Download
Downloads:
450,454
Downloads of v 2.2.0:
2,450
Maintainer(s):
Software Author(s):
- Aaron Jensen
Tags:
.net acl active-directory certificates com compression computer credential cryptography directory dsc dsc-resources encryption environment file-system firewall groups hosts-file http identity iis ini installers internet-explorer ip junctions msi msmq netsh networking ntfs operating-system os path performance-counters powershell principal privileges programs registry rsa scheduled-tasks security service shares sid smb ssl text trusted-host users wcf windows windows-features xml zip psmodule dscresources setup automation admincarbon 2.2.0
This is not the latest version of carbon available.
Legal Disclaimer: Neither this package nor Chocolatey Software, Inc. are affiliated with or endorsed by Aaron Jensen. The inclusion of Aaron Jensen trademark(s), if any, upon this webpage is solely to identify Aaron Jensen goods or services and not for commercial purposes.
- 1
- 2
- 3
All Checks are Passing
3 Passing Tests
Deployment Method: Individual Install, Upgrade, & Uninstall
To install carbon, run the following command from the command line or from PowerShell:
To upgrade carbon, run the following command from the command line or from PowerShell:
To uninstall carbon, run the following command from the command line or from PowerShell:
Deployment Method:
This applies to both open source and commercial editions of Chocolatey.
1. Enter Your Internal Repository Url
(this should look similar to https://community.chocolatey.org/api/v2/)
2. Setup Your Environment
1. Ensure you are set for organizational deployment
Please see the organizational deployment guide
2. Get the package into your environment
Option 1: Cached Package (Unreliable, Requires Internet - Same As Community)-
Open Source or Commercial:
- Proxy Repository - Create a proxy nuget repository on Nexus, Artifactory Pro, or a proxy Chocolatey repository on ProGet. Point your upstream to https://community.chocolatey.org/api/v2/. Packages cache on first access automatically. Make sure your choco clients are using your proxy repository as a source and NOT the default community repository. See source command for more information.
- You can also just download the package and push it to a repository Download
-
Open Source
-
Download the package:
Download - Follow manual internalization instructions
-
-
Package Internalizer (C4B)
-
Run: (additional options)
choco download carbon --internalize --version=2.2.0 --source=https://community.chocolatey.org/api/v2/
-
For package and dependencies run:
choco push --source="'INTERNAL REPO URL'"
- Automate package internalization
-
Run: (additional options)
3. Copy Your Script
choco upgrade carbon -y --source="'INTERNAL REPO URL'" --version="'2.2.0'" [other options]
See options you can pass to upgrade.
See best practices for scripting.
Add this to a PowerShell script or use a Batch script with tools and in places where you are calling directly to Chocolatey. If you are integrating, keep in mind enhanced exit codes.
If you do use a PowerShell script, use the following to ensure bad exit codes are shown as failures:
choco upgrade carbon -y --source="'INTERNAL REPO URL'" --version="'2.2.0'"
$exitCode = $LASTEXITCODE
Write-Verbose "Exit code was $exitCode"
$validExitCodes = @(0, 1605, 1614, 1641, 3010)
if ($validExitCodes -contains $exitCode) {
Exit 0
}
Exit $exitCode
- name: Install carbon
win_chocolatey:
name: carbon
version: '2.2.0'
source: INTERNAL REPO URL
state: present
See docs at https://docs.ansible.com/ansible/latest/modules/win_chocolatey_module.html.
chocolatey_package 'carbon' do
action :install
source 'INTERNAL REPO URL'
version '2.2.0'
end
See docs at https://docs.chef.io/resource_chocolatey_package.html.
cChocoPackageInstaller carbon
{
Name = "carbon"
Version = "2.2.0"
Source = "INTERNAL REPO URL"
}
Requires cChoco DSC Resource. See docs at https://github.com/chocolatey/cChoco.
package { 'carbon':
ensure => '2.2.0',
provider => 'chocolatey',
source => 'INTERNAL REPO URL',
}
Requires Puppet Chocolatey Provider module. See docs at https://forge.puppet.com/puppetlabs/chocolatey.
4. If applicable - Chocolatey configuration/installation
See infrastructure management matrix for Chocolatey configuration elements and examples.
This package was approved as a trusted package on 25 Jun 2016.
Carbon is a PowerShell module for automating the configuration Windows 7, 8, 2008, and 2012 and automation the installation and configuration of Windows applications, websites, and services. It can configure and manage:
- Local users and groups
- IIS websites, virtual directories, and applications
- File system, registry, and certificate permissions
- Certificates
- Privileges
- Services
- Encryption
- Junctions
- Hosts file
- INI files
- Performance counters
- Shares
- .NET connection strings and app settings
- And much more!
All functions are idempotent: when run multiple times with the same arguments, your system will be in the same state without failing or producing errors.
md5: 22A2FDE65C9EB1380EB38191355029D0 | sha1: 78E87CCE1EADBD210401E75A9AD3BDF26BDAD3E4 | sha256: 11FB3896F5D5D58EC5880E2B1D95B053707F86ED5FB7B2F62E263D9647A310C3 | sha512: BF5F7ED49D5288D8132D05F275EBCCFC107A4D390068E24469F32E494B45A910ACE9D7DAB028F568196E874DEEF878A632526720C02116C65700A91493D87101
md5: BD6E04264E641D49AC7D4FEF31698508 | sha1: E560648469AB98EEF545767DEC574550AD88E7DB | sha256: ACA5A7F9F5272922A24582EAAD2AB1A7F9A0BBD1297F735124C8DB662720B8B6 | sha512: 9C36899D4084D308BF8A6F7937FEF6FE28B786BEF95097DAA305BDAA3D8558B593045F89FEEB7F43AD4706AFDE6F4FEC62054DE1BA2575C21993505D830EDEF5
md5: 0497CD091439807BD38EC2432D8FE7C6 | sha1: BA551100A9DB21C03EC39E56F35ED3CF06D01882 | sha256: C458E1BEBBAA66A5CE7489BDC534B12AEBEB9F9BC913A7FBFC6A8AC6169F0A09 | sha512: F7D4548CCF20ABC9EA345FD3A11EC984CF4CF23C606DE03354358CE6047A4833331B00E964688B4AA1ED185588F61C80CB86F78B88D78407962D3BC3CF1C9426
md5: C7AE289C6C0D17AA8338328D6F7133BC | sha1: 2FCDB81968F586F7D76A33C61D52BF1174EE1986 | sha256: 37C70E73717FA77DCBDBD0797CACB4AB6632C4F52F090B081968C7E1E00E25B9 | sha512: 70BC9BEEBCE4436B670278853A1A5F3B9F10C30E6CE798241D1A8C1EF6C7EAA4D57D006F0443793E2D7982EA31EE3FFD59089179529321A9CF2C79B456AB47EA
md5: 5AF30A8D40E9B69689063014A5A3A5B1 | sha1: 4FFADDF2B3C86ED345C483DA70E3ABF881187EA7 | sha256: CAE1F260E08AE53C1D671BEF1DD8F90A20D08F253CAB3984EE28D055B3C754A4 | sha512: 677D541AA895B50CED9ABEFC27F6BB8C459FE32A180A6A124BB7C0A9C9C8C89D37EF94FBCCCDBF653324888A73522C064C924D4C2F46F59DD12D19FA00546425
<#
.SYNOPSIS
**INTERNAL. DO NOT USE**
#>
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
param(
[Parameter(Mandatory=$true)]
[string]
$ProtectedString
)
Set-StrictMode -Version 'Latest'
# Keep cause this script is used by PowerShell 2.
$PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
Add-Type -AssemblyName 'System.Security'
. (Join-Path -Path $PSScriptRoot -ChildPath '..\Functions\Use-CallerPreference.ps1' -Resolve)
. (Join-Path -Path $PSScriptRoot -ChildPath '..\Functions\Protect-String.ps1' -Resolve)
. (Join-Path -Path $PSScriptRoot -ChildPath '..\Functions\Unprotect-String.ps1' -Resolve)
$string = Unprotect-String -ProtectedString $ProtectedString
Protect-String -String $string -ForUser
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=0)]
[string]
$Name
)
Set-StrictMode -Version 'Latest'
# Keep cause this script is used by PowerShell 2.
$PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
. (Join-Path -Path $PSScriptRoot -ChildPath '..\Functions\Use-CallerPreference.ps1' -Resolve)
. (Join-Path -Path $PSScriptRoot -ChildPath '..\Functions\ConvertFrom-Base64.ps1' -Resolve)
$Name = $Name | ConvertFrom-Base64
Add-Type -AssemblyName System.Configuration
$config = [Configuration.ConfigurationManager]::OpenMachineConfiguration()
$appSettings = $config.AppSettings.Settings
if( $appSettings[$Name] )
{
$appSettings.Remove( $Name )
$config.Save()
}
<#
.SYNOPSIS
*Internal*. Use `Set-DotNetAppSetting` function instead.
.LINK
Set-DotNetAppSetting
#>
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=0)]
[string]
$Name,
[Parameter(Mandatory=$true,Position=1)]
[string]
$Value
)
Set-StrictMode -Version 'Latest'
# Keep cause this script is used by PowerShell 2.
$PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
. (Join-Path -Path $PSScriptRoot -ChildPath '..\Functions\Use-CallerPreference.ps1' -Resolve)
. (Join-Path -Path $PSScriptRoot -ChildPath '..\Functions\ConvertFrom-Base64.ps1' -Resolve)
$Name = $Name | ConvertFrom-Base64
$Value = $Value | ConvertFrom-Base64
Add-Type -AssemblyName System.Configuration
$config = [Configuration.ConfigurationManager]::OpenMachineConfiguration()
$appSettings = $config.AppSettings.Settings
if( $appSettings[$Name] )
{
$appSettings[$Name].Value = $Value
}
else
{
$appSettings.Add( $Name, $Value )
}
$config.Save()
<#
.SYNOPSIS
Internal. Use `Set-DotNetConnectionString` function instead.
#>
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=0)]
[string]
$Name,
[Parameter(Mandatory=$true,Position=1)]
[string]
$Value,
[Parameter(Position=2)]
[string]
$ProviderName
)
Set-StrictMode -Version 'Latest'
# Keep cause this script is used by PowerShell 2.
$PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
. (Join-Path -Path $PSScriptRoot -ChildPath '..\Functions\Use-CallerPreference.ps1' -Resolve)
. (Join-Path -Path $PSScriptRoot -ChildPath '..\Functions\ConvertFrom-Base64.ps1' -Resolve)
$Name = $Name | ConvertFrom-Base64
$Value = $Value | ConvertFrom-Base64
$ProviderName = $ProviderName | ConvertFrom-Base64
Add-Type -AssemblyName System.Configuration
$config = [Configuration.ConfigurationManager]::OpenMachineConfiguration()
$connectionStrings = $config.ConnectionStrings.ConnectionStrings
if( $connectionStrings[$Name] )
{
$connectionStrings.Remove( $Name )
}
$args = @( $Name, $Value )
if( $ProviderName )
{
$args += $ProviderName
}
$connectionString = New-Object Configuration.ConnectionStringSettings $args
$connectionStrings.Add( $connectionString )
$config.Save()
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#Requires -Version 4
$CarbonBinDir = Join-Path -Path $PSScriptRoot -ChildPath 'bin' -Resolve
. (Join-Path -Path $PSScriptRoot -ChildPath 'Functions\Test-TypeDataMember.ps1' -Resolve)
. (Join-Path -Path $PSScriptRoot -ChildPath 'Functions\Use-CallerPreference.ps1' -Resolve)
$doNotImport = @{ }
$functionRoot = Join-Path -Path $PSScriptRoot -ChildPath 'Functions' -Resolve
# Active Directory
# COM
$ComRegKeyPath = 'hklm:\software\microsoft\ole'
# Cryptography
Add-Type -AssemblyName 'System.Security'
# FileSystem
Add-Type -Path (Join-Path -Path $PSScriptRoot -ChildPath 'bin\Ionic.Zip.dll' -Resolve)
# IIS
Add-Type -AssemblyName "System.Web"
$microsoftWebAdministrationPath = Join-Path -Path $env:SystemRoot -ChildPath 'system32\inetsrv\Microsoft.Web.Administration.dll'
if( (Test-Path -Path $microsoftWebAdministrationPath -PathType Leaf) )
{
Add-Type -Path $microsoftWebAdministrationPath
Add-Type -Path (Join-Path -Path $CarbonBinDir -ChildPath 'Carbon.Iis.dll' -Resolve)
if( -not (Test-TypeDataMember -TypeName 'Microsoft.Web.Administration.Site' -MemberName 'PhysicalPath') )
{
Update-TypeData -TypeName 'Microsoft.Web.Administration.Site' -MemberType ScriptProperty -MemberName 'PhysicalPath' -Value {
$this.Applications |
Where-Object { $_.Path -eq '/' } |
Select-Object -ExpandProperty VirtualDirectories |
Where-Object { $_.Path -eq '/' } |
Select-Object -ExpandProperty PhysicalPath
}
}
if( -not (Test-TypeDataMember -TypeName 'Microsoft.Web.Administration.Application' -MemberName 'PhysicalPath') )
{
Update-TypeData -TypeName 'Microsoft.Web.Administration.Application' -MemberType ScriptProperty -MemberName 'PhysicalPath' -Value {
$this.VirtualDirectories |
Where-Object { $_.Path -eq '/' } |
Select-Object -ExpandProperty PhysicalPath
}
}
}
else
{
Get-ChildItem -Path $functionRoot -Filter '*-Iis*.ps1' |
ForEach-Object { $doNotImport[$_.Name] = $true }
}
# MSMQ
Add-Type -AssemblyName 'System.ServiceProcess'
Add-Type -AssemblyName 'System.Messaging'
#PowerShell
$TrustedHostsPath = 'WSMan:\localhost\Client\TrustedHosts'
# Services
Add-Type -AssemblyName 'System.ServiceProcess'
# Users and Groups
Add-Type -AssemblyName 'System.DirectoryServices.AccountManagement'
# Windows Features
$useServerManager = (Get-Command -Name 'servermanagercmd.exe' -ErrorAction Ignore) -ne $null
$useWmi = $false
$useOCSetup = $false
if( -not $useServerManager )
{
$useWmi = (Get-WmiObject -List -Class 'Win32_OptionalFeature') -ne $null
$useOCSetup = (Get-Command -Name 'ocsetup.exe' -ErrorAction Ignore ) -ne $null
}
$windowsFeaturesNotSupported = (-not ($useServerManager -or ($useWmi -and $useOCSetup) ))
$supportNotFoundErrorMessage = 'Unable to find support for managing Windows features. Couldn''t find servermanagercmd.exe, ocsetup.exe, or WMI support.'
# Extended Type
if( -not (Test-TypeDataMember -TypeName 'System.IO.FileInfo' -MemberName 'GetCarbonFileInfo') )
{
Update-TypeData -TypeName 'System.IO.FileInfo' -MemberType ScriptMethod -MemberName 'GetCarbonFileInfo' -Value {
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the Carbon file info property to get.
$Name
)
Set-StrictMode -Version 'Latest'
if( -not $this.Exists )
{
return
}
if( -not ($this | Get-Member -Name 'CarbonFileInfo') )
{
$this | Add-Member -MemberType NoteProperty -Name 'CarbonFileInfo' -Value (New-Object 'Carbon.IO.FileInfo' $this.FullName)
}
if( $this.CarbonFileInfo | Get-Member -Name $Name )
{
return $this.CarbonFileInfo.$Name
}
}
}
if( -not (Test-TypeDataMember -TypeName 'System.IO.FileInfo' -MemberName 'FileIndex') )
{
Update-TypeData -TypeName 'System.IO.FileInfo' -MemberType ScriptProperty -MemberName 'FileIndex' -Value {
Set-StrictMode -Version 'Latest'
return $this.GetCarbonFileInfo( 'FileIndex' )
}
}
if( -not (Test-TypeDataMember -TypeName 'System.IO.FileInfo' -MemberName 'LinkCount') )
{
Update-TypeData -TypeName 'System.IO.FileInfo' -MemberType ScriptProperty -MemberName 'LinkCount' -Value {
Set-StrictMode -Version 'Latest'
return $this.GetCarbonFileInfo( 'LinkCount' )
}
}
if( -not (Test-TypeDataMember -TypeName 'System.IO.FileInfo' -MemberName 'VolumeSerialNumber') )
{
Update-TypeData -TypeName 'System.IO.FileInfo' -MemberType ScriptProperty -MemberName 'VolumeSerialNumber' -Value {
Set-StrictMode -Version 'Latest'
return $this.GetCarbonFileInfo( 'VolumeSerialNumber' )
}
}
Get-ChildItem -Path $functionRoot -Filter '*.ps1' |
Where-Object { -not $doNotImport.Contains($_.Name) } |
ForEach-Object {
Write-Verbose ("Importing function {0}." -f $_.FullName)
. $_.FullName | Out-Null
}
$module = Test-ModuleManifest -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Carbon.psd1' -Resolve)
if( -not $module )
{
return
}
Export-ModuleMember -Alias '*' -Function ([string[]]$module.ExportedFunctions.Keys)
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
& (Join-Path -Path $PSScriptRoot -ChildPath '..\Initialize-CarbonDscResource.ps1' -Resolve)
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([Collections.Hashtable])]
param
(
[Parameter(Mandatory=$true)]
[string]
# The name of the environment variable.
$Name,
[string]
# the value of the environment variable.
$Value,
[ValidateSet("Present","Absent")]
[string]
# Create or delete the resource?
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$actualValue = [Environment]::GetEnvironmentVariable($Name,[EnvironmentVariableTarget]::Machine)
$Ensure = 'Present'
if( $actualValue -eq $null )
{
$Ensure = 'Absent'
}
@{
Name = $Name;
Ensure = $Ensure;
Value = $actualValue;
}
}
function Set-TargetResource
{
<#
.SYNOPSIS
DSC resource for managing environment variables.
.DESCRIPTION
The Carbon_EnvironmentVariable resource will add, update, or remove environment variables. The environment variable is set/removed at both the computer *and* process level, so that the process applying the DSC configuration will have access to the variable in later resources.
`Carbon_EnvironmentVariable` is new in Carbon 2.0.
.LINK
Set-EnvironmentVariable
.EXAMPLE
>
Demonstrates how to create or update an environment variable:
Carbon_EnvironmentVariable SetCarbonEnv
{
Name = 'CARBON_ENV';
Value = 'developer';
Ensure = 'Present';
}
.EXAMPLE
>
Demonstrates how to remove an environment variable.
Carbon_EnvironmentVariable RemoveCarbonEnv
{
Name = 'CARBON_ENV';
Ensure = 'Absent';
}
#>
[CmdletBinding()]
param
(
[parameter(Mandatory = $true)]
[string]
# The name of the environment variable.
$Name,
[string]
# The value of the environment variable.
$Value,
[ValidateSet("Present","Absent")]
[string]
# Set to `Present` to create the environment variable. Set to `Absent` to delete it.
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
if( $Ensure -eq 'Absent' )
{
Write-Verbose ('{0}: removing' -f $Name)
}
[Environment]::SetEnvironmentVariable($Name,$null,([EnvironmentVariableTarget]::Machine))
[Environment]::SetEnvironmentVariable($Name,$null,([EnvironmentVariableTarget]::Process))
if( $Ensure -eq 'Present' )
{
Write-Verbose ('{0}: setting' -f $Name)
Set-EnvironmentVariable -Name $Name -Value $Value -ForComputer -ForProcess
}
}
function Test-TargetResource
{
[CmdletBinding()]
[OutputType([System.Boolean])]
param
(
[parameter(Mandatory = $true)]
[String]
$Name,
[String]
$Value,
[ValidateSet("Present","Absent")]
[String]
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$resource = $null
$resource = Get-TargetResource -Name $Name
if( $Ensure -eq 'Present' )
{
$result = ($resource.Value -eq $Value);
if( $result )
{
Write-Verbose ('{0}: value OK' -f $Name)
}
else
{
Write-Verbose ('{0}: value differs' -f $Name)
}
return $result
}
else
{
$result = ($resource.Value -eq $null)
if( $result )
{
Write-Verbose ('{0}: has no value' -f $Name)
}
else
{
Write-Verbose ('{0}: has a value' -f $Name)
}
return $result
}
$false
}
Export-ModuleMember -Function '*-TargetResource'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
& (Join-Path -Path $PSScriptRoot -ChildPath '..\Initialize-CarbonDscResource.ps1' -Resolve)
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([Hashtable])]
param (
[Parameter(Mandatory=$true)]
[string]
$Name,
[bool]
$Enabled = $true,
[ValidateSet('In','Out')]
[string]
$Direction,
[ValidateSet('Any','Domain','Private','Public')]
[string[]]
$Profile = @( 'Any' ),
[string]
$LocalIPAddress = 'Any',
[string]
$LocalPort,
[string]
$RemoteIPAddress = 'Any',
[string]
$RemotePort,
[string]
$Protocol = 'Any',
[ValidateSet('Yes', 'No', 'DeferUser','DeferApp')]
[string]
$EdgeTraversalPolicy = 'No',
[ValidateSet('Allow','Block','Bypass')]
[string]
$Action,
[ValidateSet('Any','Wireless','LAN','RAS')]
[string]
$InterfaceType = 'Any',
[ValidateSet('NotRequired','Authenticate','AuthEnc','AuthDynEnc','AuthNoEncap')]
[string]
$Security = 'NotRequired',
[string]
$Description,
[string]
$Program,
[string]
$Service,
[ValidateSet('Present','Absent')]
[string]
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$rule = Get-FirewallRule -LiteralName $Name
if( $rule -is [object[]] )
{
Write-Error ('Found {0} firewall rules named ''{1}''.' -f $rule.Count,$Name)
return
}
$resource = @{
'Action' = $Action;
'Description' = $Description;
'Direction' = $Direction;
'EdgeTraversalPolicy' = $EdgeTraversalPolicy
'Enabled' = $Enabled;
'Ensure' = 'Absent';
'InterfaceType' = $InterfaceType
'LocalIPAddress' = $LocalIPAddress;
'LocalPort' = $LocalPort;
'Name' = $Name;
'Profile' = $Profile;
'Program' = $Program;
'Protocol' = $Protocol;
'RemoteIPAddress' = $RemoteIPAddress;
'RemotePort' = $RemotePort;
'Security' = $Security;
'Service' = $Service;
}
if( $rule )
{
$propNames = $resource.Keys | ForEach-Object { $_ }
$propNames |
Where-Object { $_ -ne 'Ensure' } |
ForEach-Object {
$propName = $_
switch( $propName )
{
'Profile' { $value = $rule.Profile.ToString() -split ', ' }
'Enabled' { $value = $rule.Enabled }
default
{
$value = ($rule.$propName).ToString()
}
}
$resource[$propName] = $value
}
$resource.Ensure = 'Present'
}
return $resource
}
function Set-TargetResource
{
<#
.SYNOPSIS
DSC resource for managing firewall rules.
.DESCRIPTION
The `Carbon_FirewallRule` resource manages firewall rules. It uses the `netsh advfirewall firewall` command. Please see [Netsh AdvFirewall Firewall Commands](http://technet.microsoft.com/en-us/library/dd734783.aspx) or run `netsh advfirewall firewall set rule` for documentation on how to configure the firewall.
When modifying existing rules, only properties you pass are updated/changed. All other properties are left as-is.
`Carbon_FirewallRule` is new in Carbon 2.0.
.LINK
Get-FirewallRule
.LINK
http://technet.microsoft.com/en-us/library/dd734783.aspx
.EXAMPLE
>
Demonstrates how to enable a firewall rule.
Carbon_FirewallRule EnableHttpIn
{
Name = 'World Wide Web Services (HTTP Traffic-In)'
Enabled = $true;
Ensure = 'Present'
}
.EXAMPLE
>
Demonstrates how to delete a firewall rule.
Carbon_FirewallRule DeleteMyRule
{
Name = 'MyCustomRule';
Ensure = 'Absent';
}
There may be multiple rules with the same name, so we recommend disabling rules instead.
.EXAMPLE
>
Demonstrates how to create/modify an incoming firewall rule.
Carbon_FirewallRule MyAppPorts
{
Name = 'My App Ports';
Action = 'Allow';
Direction = 'In';
Protocol = 'tcp';
LocalPort = '8080,8180';
Ensure = 'Present';
}
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]
# The name of the rule.
$Name,
[bool]
# If `$true`, the rule is enabled. If `$false`, the rule is disabled.
$Enabled = $true,
[ValidateSet('In','Out')]
[string]
# If set to `In`, the rule applies to inbound network traffic. If set to `Out`, the rule applies to outbound traffic.
$Direction,
[ValidateSet('Any','Domain','Private','Public')]
[string[]]
# Specifies the profile(s) to which the firewall rule is assigned. The rule is active on the local computer only when the specified profile is currently active. Valid values are `Any`, `Domain`, `Public`, and `Private`.
$Profile,
[string]
# The local IP addresses the rule applies to. Valid values are `any`, an exact IPv4 or IPv6 address, a subnet mask (e.g. 192.168.0.0/24), or a range. Separate each value with a comma; no spaces.
$LocalIPAddress,
[string]
# The local port the rule applies to. Valid values are a specific port number, a range of port numbers (e.g. `5000-5010`), a comma-separate list of numbers and ranges, `any`, `rpc`, `rpc-epmap`, `Teredo`, and `iphttps`.
$LocalPort,
[string]
# The remote IP addresses the rules applies to. Valid values are `any`, an exact IPv4 or IPv6 address, a subnet mask (e.g. 192.168.0.0/24), or a range. Separate each value with a comma; no spaces.
$RemoteIPAddress,
[string]
# The remote port the rule applies to. Valid values are a specific port number, a range of port numbers (e.g. `5000-5010`), a comma-separate list of numbers and ranges, `any`, `rpc`, `rpc-epmap`, `Teredo`, and `iphttps`.
$RemotePort,
[string]
# The protocol the rule applies to. Valid values are `any`, the protocol number, `icmpv4`, `icmpv6', `icmpv4:type,code`, `icmpv6:type,code`, `tcp`, or `udp`. Separate multiple values with a comma; no spaces.
$Protocol,
[ValidateSet('Yes', 'No', 'DeferUser','DeferApp')]
[string]
# For inbound rules, specifies that traffic that traverses an edge device, such as a Network Address Translation (NAT) enabled router, between the local and remote computer matches this rule. Valid values are `any`, `deferapp`, `deferuse`, or `no`.
$EdgeTraversalPolicy,
[ValidateSet('Allow','Block','Bypass')]
[string]
# Specifies what to do when packets match the rule. Valid values are `Allow`, `Block`, or `Bypass`.
$Action,
[ValidateSet('Any','Wireless','LAN','RAS')]
[string]
# Specifies that only network packets passing through the indicated interface types match this rule. Valid values are `Any`, `Wireless`, `LAN`, or `RAS`.
$InterfaceType,
[ValidateSet('NotRequired','Authenticate','AuthEnc','AuthDynEnc','AuthNoEncap')]
[string]
# Specifies that only network packets protected with the specified type of IPsec options match this rule. Valid values are `NotRequired`, `Authenticate`, `AuthEnc`, `AuthDynEnc`, or `AuthNoEncap`.
$Security,
[string]
# A description of the rule.
$Description,
[string]
# Specifies that network traffic generated by the identified executable program matches this rule.
$Program,
[string]
# Specifies that traffic generated by the identified service matches this rule. The ServiceShortName for a service can be found in Services MMC snap-in, by right-clicking the service, selecting Properties, and examining Service Name.
$Service,
[ValidateSet('Present','Absent')]
[string]
# Set to `Present` to create the fireall rule. Set to `Absent` to delete it.
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$resource = Get-TargetResource -Name $Name
if( $Ensure -eq 'Absent' -and $resource.Ensure -eq 'Present' )
{
Write-Verbose ('Deleting firewall rule ''{0}''' -f $Name)
$output = netsh advfirewall firewall delete rule name=$Name
if( $LASTEXITCODE )
{
Write-Error ($output -join ([Environment]::NewLine))
return
}
$output | Write-Verbose
return
}
$cmd = 'add'
$cmdDisplayName = 'Adding'
$newArg = ''
if( $Ensure -eq 'Present' -and $resource.Ensure -eq 'Present' )
{
$cmd = 'set'
$cmdDisplayName = 'Setting'
$newArg = 'new'
}
else
{
if( -not $Direction -and -not $Action )
{
Write-Error ('Parameters ''Direction'' and ''Action'' are required when adding a new firewall rule.')
return
}
elseif( -not $Direction )
{
Write-Error ('Parameter ''Direction'' is required when adding a new firewall rule.')
return
}
elseif( -not $Action )
{
Write-Error ('Parameter ''Action'' is required when adding a new firewall rule.')
return
}
}
$argMap = @{
'Direction' = 'dir';
'Enabled' = 'enable';
'LocalIPAddress' = 'localip';
'RemoteIPAddress' = 'remoteip';
'EdgeTraversalPolicy' = 'edge';
}
$netshArgs = New-Object 'Collections.Generic.List[string]'
$resource.Keys |
Where-Object { $_ -ne 'Ensure' -and $_ -ne 'Name' } |
Where-Object { $PSBoundParameters.ContainsKey($_) } |
ForEach-Object {
$argName = $_.ToLowerInvariant()
$argValue = $PSBoundParameters[$argName]
if( $argValue -is [bool] )
{
$argValue = if( $argValue ) { 'yes' } else { 'no' }
}
if( $argMap.ContainsKey($argName) )
{
$argName = $argMap[$argName]
}
[void]$netshArgs.Add( ('{0}=' -f $argName) )
[void]$netshArgs.Add( $argValue )
}
Write-Verbose ('{0} firewall rule ''{1}''' -f $cmdDisplayName,$Name)
$output = netsh advfirewall firewall $cmd rule name= $Name $newArg $netshArgs
if( $LASTEXITCODE )
{
Write-Error ($output -join ([Environment]::NewLine))
return
}
$output | Write-Verbose
}
function Test-TargetResource
{
[CmdletBinding()]
[OutputType([bool])]
param (
[Parameter(Mandatory=$true)]
[string]
$Name,
[bool]
$Enabled,
[ValidateSet('In','Out')]
[string]
$Direction,
[ValidateSet('Any','Domain','Private','Public')]
[string[]]
$Profile,
[string]
$LocalIPAddress,
[string]
$LocalPort,
[string]
$RemoteIPAddress,
[string]
$RemotePort,
[string]
$Protocol,
[ValidateSet('Yes', 'No', 'DeferUser','DeferApp')]
[string]
$EdgeTraversalPolicy,
[ValidateSet('Allow','Block','Bypass')]
[string]
$Action,
[ValidateSet('Any','Wireless','LAN','RAS')]
[string]
$InterfaceType,
[ValidateSet('NotRequired','Authenticate','AuthEnc','AuthDynEnc','AuthNoEncap')]
[string]
$Security,
[string]
$Description,
[string]
$Program,
[string]
$Service,
[ValidateSet('Present','Absent')]
[string]
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$resource = Get-TargetResource @PSBoundParameters
if( $Ensure -eq 'Absent' )
{
$result = ($resource.Ensure -eq 'Absent')
if( $result )
{
Write-Verbose ('Firewall rule ''{0}'' not found.' -f $Name)
}
else
{
Write-Verbose ('Firewall rule ''{0}'' found.' -f $Name)
}
return $result
}
if( $Ensure -eq 'Present' -and $resource.Ensure -eq 'Absent' )
{
Write-Verbose ('Firewall rule ''{0}'' not found.' -f $Name)
return $false
}
return Test-DscTargetResource -TargetResource $resource -DesiredResource $PSBoundParameters -Target ('Firewall rule ''{0}''' -f $Name)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
& (Join-Path -Path $PSScriptRoot -ChildPath '..\Initialize-CarbonDscResource.ps1' -Resolve)
. (Join-Path -Path $PSScriptRoot -ChildPath '..\..\Functions\Use-CallerPreference.ps1' -Resolve)
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([hashtable])]
param
(
[parameter(Mandatory = $true)]
[System.String]
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$group = Get-Group -Name $Name -ErrorAction Ignore
$ensure = 'Absent'
$description = $null
$members = @()
if( $group )
{
$description = $group.Description
$members = $group.Members
$ensure = 'Present'
}
@{
Name = $Name
Ensure = $ensure
Description = $description
Members = $members
}
}
function Set-TargetResource
{
<#
.SYNOPSIS
DSC resource for configuring local Windows groups.
.DESCRIPTION
The `Carbon_Group` resource installs and uninstalls groups. It also adds members to existing groups.
The group is installed when `Ensure` is set to `Present`. Members of the group are updated to match the `Members` property (i.e. members not listed in the `Members` property are removed from the group). If `Members` has no value, all members are removed. Because DSC resources run under the LCM which runs as `System`, local system accounts must have access to the directories where both new and existing member accounts can be found.
The group is removed when `Ensure` is set to `Absent`. When removing a group, the `Members` property is ignored.
The `Carbon_Group` resource was added in Carbon 2.1.0.
.LINK
Add-GroupMember
.LINK
Install-Group
.LINK
Remove-GroupMember
.LINK
Test-Group
.LINK
Uninstall-Group
.EXAMPLE
>
Demonstrates how to install a group and add members to it.
Carbon_Group 'CreateFirstOrder'
{
Name = 'FirstOrder';
Description = 'On to victory!';
Ensure = 'Present';
Members = @( 'FO\SupremeLeaderSnope', 'FO\KRen' );
}
.EXAMPLE
>
Demonstrates how to uninstall a group.
Carbon_Group 'RemoveRepublic
{
Name = 'Republic';
Ensure = 'Absent';
}
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param
(
[parameter(Mandatory=$true)]
[string]
# The name of the group.
$Name,
[string]
# A description of the group. Only used when adding/updating a group (i.e. when `Ensure` is `Present`).
$Description,
[ValidateSet("Present","Absent")]
[string]
# Should be either `Present` or `Absent`. If set to `Present`, a group is configured and membership configured. If set to `Absent`, the group is removed.
$Ensure,
[string[]]
# The group's members. Only used when adding/updating a group (i.e. when `Ensure` is `Present`).
#
# Members not in this list are removed from the group.
$Members = @()
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $Ensure -eq 'Absent' )
{
Uninstall-Group -Name $Name
return
}
$group = Install-Group -Name $Name -Description $Description -Member $Members -PassThru
if( -not $group )
{
return
}
try
{
$memberNames = @()
if( $Members )
{
$memberNames = $Members | Resolve-MemberName
}
$membersToRemove = $group.Members | Where-Object {
$memberName = Resolve-PrincipalName -Principal $_
return $memberNames -notcontains $memberName
}
if( $membersToRemove )
{
foreach( $memberToRemove in $membersToRemove )
{
Write-Verbose -Message ('[{0}] Members {1} ->' -f $Name,(Resolve-PrincipalName -Principal $memberToRemove))
$group.Members.Remove( $memberToRemove )
}
if( $PSCmdlet.ShouldProcess( ('local group {0}' -f $Name), 'remove members' ) )
{
$group.Save()
}
}
}
finally
{
$group.Dispose()
}
}
function Test-TargetResource
{
[CmdletBinding()]
[OutputType([bool])]
param
(
[parameter(Mandatory = $true)]
[string]
$Name,
[string]
$Description = $null,
[ValidateSet("Present","Absent")]
[string]
$Ensure = "Present",
[string[]]
$Members = @()
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$resource = Get-TargetResource -Name $Name
# Do we need to delete the group?
if( $Ensure -eq 'Absent' -and $resource.Ensure -eq 'Present' )
{
Write-Verbose -Message ('[{0}] Group is present but should be absent.' -f $Name)
return $false
}
# Is it already gone?
if( $Ensure -eq 'Absent' -and $resource.Ensure -eq 'Absent' )
{
return $true
}
# Do we need to create the group?
if( $Ensure -eq 'Present' -and $resource.Ensure -eq 'Absent' )
{
Write-Verbose -Message ('[{0}] Group is absent but should be present.' -f $Name)
return $false
}
# Is the group out-of-date?
$upToDate = $true
if( $Description -ne $resource.Description )
{
Write-Verbose -Message ('[{0}] [Description] ''{1}'' != ''{2}''' -f $Name,$Description,$resource.Description)
$upToDate = $false
}
$memberNames = @()
if( $Members )
{
$memberNames = $Members | Resolve-MemberName
}
$currentMemberNames = $resource['Members'] | Resolve-PrincipalName
# Is the current group missing the desired members?
foreach( $memberName in $memberNames )
{
if( $currentMemberNames -notcontains $memberName )
{
Write-Verbose -Message ('[{0}] [Members] {1} is absent but should be present' -f $Name,$memberName)
$upToDate = $false
}
}
# Does the current group contains extra members?
foreach( $memberName in $currentMemberNames )
{
if( $memberNames -notcontains $memberName )
{
Write-Verbose -Message ('[{0}] [Members] {1} is present but should be absent' -f $Name,$memberName)
$upToDate = $false
}
}
return $upToDate
}
function Resolve-MemberName
{
param(
[Parameter(Mandatory=$true,VAlueFromPipeline=$true)]
[string]
$Name
)
process
{
Resolve-IdentityName -Name $Name
}
}
function Resolve-PrincipalName
{
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
$Principal
)
process
{
Resolve-Identity -SID $Principal.Sid.Value | Select-Object -ExpandProperty 'FullName'
}
}
Export-ModuleMember -Function *-TargetResource
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
& (Join-Path -Path $PSScriptRoot -ChildPath '..\Initialize-CarbonDscResource.ps1' -Resolve)
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([Collections.Hashtable])]
param
(
[Parameter(Mandatory=$true)]
[string]
# The path to the file to update.
$Path,
[string]
# The section of the INI file where the setting can be found.
$Section,
[Parameter(Mandatory=$true)]
[string]
# The name of the INI setting.
$Name,
[string]
# The value of the INI setting.
$Value,
[Switch]
# The INI file being modified is case-sensitive.
$CaseSensitive,
[Switch]
# If `$true`, creates the INI file if it doesn't exist.
$Force,
[ValidateSet("Present","Absent")]
[string]
# Create or delete the INI setting?
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$ini = @{ }
if( (Test-Path -Path $Path -PathType Leaf) )
{
$ini = Split-Ini -Path $Path -AsHashtable -CaseSensitive:$CaseSensitive
}
else
{
if( -not $Force )
{
Write-Error ('INI file ''{0}'' not found. Set the `Force` property to `true` to create this INI file when it doesn''t exist.' -f $Path)
return
}
}
$key = $Name
if( $Section )
{
$key = '{0}.{1}' -f $Section,$Name
}
$currentValue = $null
$Ensure = 'Absent'
if( $ini.ContainsKey( $key ) )
{
$currentValue = $ini[$key].Value
$Ensure = 'Present';
}
@{
Path = $Path;
Section = $Section;
Name = $Name;
Value = $currentValue;
CaseSensitive = [bool]$CaseSensitive;
Force = [bool]$Force
Ensure = $Ensure;
}
}
function Set-TargetResource
{
<#
.SYNOPSIS
DSC resource for managing settings in INI files.
.DESCRIPTION
The `Carbon_IniFile` resource sets or removes settings from INI files.
`Carbon_IniFile` is new in Carbon 2.0.
.LINK
Remove-IniEntry
.LINK
Set-IniEntry
.LINK
Split-Ini
.EXAMPLE
>
Demonstrates how to create/set a setting in sectionless INI file.
Carbon_IniFile SetNpmPrefix
{
Path = 'C:\Program Files\nodejs\node_modules\npm\npmrc'
Name = 'prefix';
Value = 'C:\node-global-modules';
CaseSensitive = $true;
}
In this case, we're setting the `prefix` NPM setting to `C:\node-global-modules` in the `C:\Program Files\nodejs\node_modules\npm\npmrc` file. It is expected this file exists and you'll get an error if it doesn't. NPM configuration files are case-sensitive, so the `CaseSensitive` property is set to `$true`.
This line will be added to the INI file:
prefix = C:\node-global-modules
.EXAMPLE
>
Demonstrates how to create/set a setting in an INI file with sections.
Carbon_IniFile SetBuildUserMercurialUsername
{
Path = 'C:\Users\BuildUser\mercurial.ini'
Section = 'ui';
Name = 'username';
Force = $true;
Value = 'Build User <[email protected]>';
}
In this case, we're setting the 'username' setting in the 'ui' section of the `C:\Users\BuildUser\mercurial.ini` file to `Build User <[email protected]>`. Since the `$Force` property is `$true`, if the file doesn't exist, it will be created. These lines will be added to the ini file:
[ui]
username = Build User <[email protected]>
.EXAMPLE
>
Demonstrates how to remove a setting from a case-sensitive INI file.
Carbon_IniFile RemoveNpmPrefix
{
Path = 'C:\Program Files\nodejs\node_modules\npm\npmrc'
Name = 'prefix';
CaseSensitive = $true;
Ensure = 'Absent';
}
.EXAMPLE
>
Demonstrates how to remove a setting from an INI file that organizes settings into sections.
Carbon_IniFile RemoveBuildUserMercurialUsername
{
Path = 'C:\Users\BuildUser\mercurial.ini'
Section = 'ui';
Name = 'username';
Ensure = 'Absent';
}
#>
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true)]
[string]
# The path to the file to update.
$Path,
[string]
# The section of the INI file where the setting can be found.
$Section,
[Parameter(Mandatory=$true)]
[string]
# The name of the INI setting.
$Name,
[string]
# The value of the INI setting.
$Value,
[Switch]
# The INI file being modified is case-sensitive.
$CaseSensitive,
[Switch]
# If `$true`, creates the INI file if it doesn't exist.
$Force,
[ValidateSet("Present","Absent")]
[string]
# Create or delete the INI setting?
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$resource = Get-TargetResource -Path $Path -Section $Section -Name $Name -Force:$Force -CaseSensitive:$CaseSensitive
if( -not $resource )
{
return
}
if( -not (Test-Path -Path $Path -PathType Leaf) -and $Force )
{
New-Item -Path $Path -ItemType 'File' -Force | Out-Null
}
$fullName = $Name
if( $Section )
{
$fullName = '{0}.{1}' -f $Section,$Name
}
if( $resource.Ensure -eq 'Present' -and $Ensure -eq 'Absent' )
{
Write-Verbose ('{0}: {1}: removing' -f $Path,$fullName)
Remove-IniEntry -Path $Path -Section $Section -Name $Name -CaseSensitive:$CaseSensitive
return
}
if( $Ensure -eq 'Present' )
{
Write-Verbose ('{0}: {1}: setting' -f $Path,$fullName)
Set-IniEntry -Path $Path -Section $Section -Name $Name -Value $Value -CaseSensitive:$CaseSensitive
}
}
function Test-TargetResource
{
[CmdletBinding()]
[OutputType([bool])]
param
(
[Parameter(Mandatory=$true)]
[string]
# The path to the file to update.
$Path,
[string]
# The section of the INI file where the setting can be found.
$Section,
[Parameter(Mandatory=$true)]
[string]
# The name of the INI setting.
$Name,
[string]
# The value of the INI setting.
$Value,
[Switch]
# The INI file being modified is case-sensitive.
$CaseSensitive,
[Switch]
# If `$true`, creates the INI file if it doesn't exist.
$Force,
[ValidateSet("Present","Absent")]
[string]
# Create or delete the INI setting?
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$resource = Get-TargetResource -Path $Path -Section $Section -Name $Name -Force:$Force
if( -not $resource )
{
return $false
}
$fullName = $Name
if( $Section )
{
$fullName = '{0}.{1}' -f $Section,$Name
}
if( $Ensure -eq 'Present' )
{
$result = ($resource.Value -eq $Value)
if( $CaseSensitive )
{
$result = ($resource.Value -ceq $Value)
}
if( $result )
{
Write-Verbose ('{0}: {1}: current value unchanged' -f $Path,$fullName)
}
else
{
Write-Verbose ('{0}: {1}: current value differs' -f $Path,$fullName)
}
}
else
{
$result = ($resource.Ensure -eq 'Absent')
if( $result )
{
Write-Verbose ('{0}: {1}: not found' -f $Path,$fullName)
}
else
{
Write-Verbose ('{0}: {1}: found' -f $Path,$fullName)
}
}
return $result
}
Export-ModuleMember -Function '*-TargetResource'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
& (Join-Path -Path $PSScriptRoot -ChildPath '..\Initialize-CarbonDscResource.ps1' -Resolve)
function Get-TargetResource
{
[CmdletBinding(SupportsShouldProcess=$true)]
[OutputType([hashtable])]
param(
[Parameter(Mandatory=$true)]
[string]
# The identity of the principal whose privileges to get.
$Identity,
[AllowEmptyCollection()]
[string[]]
# The user's expected/desired privileges.
$Privilege = @(),
[ValidateSet('Present','Absent')]
[string]
# Should the user exist or not exist?
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
[string[]]$currentPrivileges = Get-Privilege -Identity $Identity
$Ensure = 'Present'
if( -not $currentPrivileges )
{
[string[]]$currentPrivileges = @()
}
foreach( $item in $Privilege )
{
if( $currentPrivileges -notcontains $item )
{
$Ensure = 'Absent'
break
}
}
foreach( $item in $currentPrivileges )
{
if( $Privilege -notcontains $item )
{
$Ensure = 'Absent'
break
}
}
$resource = @{
Identity = $Identity;
Privilege = $currentPrivileges;
Ensure = $Ensure;
}
return $resource
}
function Set-TargetResource
{
<#
.SYNOPSIS
DSC resource for managing privileges.
.DESCRIPTION
The `Carbon_Privilege` resource manages privileges, i.e. the system operations and logons a user or group can perform.
Privileges are granted by default. The user/group is granted only the privileges specified by the `Privilege` property. All other privileges are revoked.
To revoke *all* a user's privileges, set the `Ensure` property to `Absent`. To revoke specific privileges, grant the user just the desired privileges. All others are revoked.
*Privilege names are **case-sensitive**.* Valid privileges are documented on Microsoft's website: [Privilege Constants](http://msdn.microsoft.com/en-us/library/windows/desktop/bb530716.aspx) and [Account Right Constants](http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671.aspx). Here is the most current list, as of August 2014:
* SeAssignPrimaryTokenPrivilege
* SeAuditPrivilege
* SeBackupPrivilege
* SeBatchLogonRight
* SeChangeNotifyPrivilege
* SeCreateGlobalPrivilege
* SeCreatePagefilePrivilege
* SeCreatePermanentPrivilege
* SeCreateSymbolicLinkPrivilege
* SeCreateTokenPrivilege
* SeDebugPrivilege
* SeDenyBatchLogonRight
* SeDenyInteractiveLogonRight
* SeDenyNetworkLogonRight
* SeDenyRemoteInteractiveLogonRight
* SeDenyServiceLogonRight
* SeEnableDelegationPrivilege
* SeImpersonatePrivilege
* SeIncreaseBasePriorityPrivilege
* SeIncreaseQuotaPrivilege
* SeIncreaseWorkingSetPrivilege
* SeInteractiveLogonRight
* SeLoadDriverPrivilege
* SeLockMemoryPrivilege
* SeMachineAccountPrivilege
* SeManageVolumePrivilege
* SeNetworkLogonRight
* SeProfileSingleProcessPrivilege
* SeRelabelPrivilege
* SeRemoteInteractiveLogonRight
* SeRemoteShutdownPrivilege
* SeRestorePrivilege
* SeSecurityPrivilege
* SeServiceLogonRight
* SeShutdownPrivilege
* SeSyncAgentPrivilege
* SeSystemEnvironmentPrivilege
* SeSystemProfilePrivilege
* SeSystemtimePrivilege
* SeTakeOwnershipPrivilege
* SeTcbPrivilege
* SeTimeZonePrivilege
* SeTrustedCredManAccessPrivilege
* SeUndockPrivilege
* SeUnsolicitedInputPrivilege
`Carbon_Privilege` is new in Carbon 2.0.
.LINK
Get-Privilege
.LINK
Grant-Privilege
.LINK
Revoke-Privilege
.LINK
Test-Privilege
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/bb530716.aspx
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671.aspx
.EXAMPLE
>
Demonstrates how to grant a service user the ability to log in as a service.
Carbon_Privilege GrantServiceLogonPrivileges
{
Identity = 'CarbonServiceUser'
Privilege = 'SeBatchLogonRight','SeServiceLogonRight';
}
.EXAMPLE
>
Demonstrates how to revoke all a user/group's privileges. To revoke specific privileges, grant just the privileges you want. All other privileges are revoked.
Carbon_Privilege RevokePrivileges
{
Identity = 'CarbonServiceUser'
Ensure = 'Absent'
}
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The identity of the principal whose privileges to set.
$Identity,
[AllowEmptyCollection()]
[string[]]
# The user's expected/desired privileges. *Privilege names are **case-sensitive**.* Ignored when `Ensure` is set to `Absent`.
$Privilege = @(),
[ValidateSet('Present','Absent')]
[string]
# Should the user exist or not exist?
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$currentPrivileges = Get-Privilege -Identity $Identity
if( $currentPrivileges )
{
Write-Verbose ('Revoking ''{0}'' privileges: {1}' -f $Identity,($currentPrivileges -join ','))
Revoke-Privilege -Identity $Identity -Privilege $currentPrivileges
}
if( $Ensure -eq 'Present' -and $Privilege )
{
Write-Verbose ('Granting ''{0}'' privileges: {1}' -f $Identity,($Privilege -join ','))
Grant-Privilege -Identity $Identity -Privilege $Privilege
}
}
function Test-TargetResource
{
[CmdletBinding(SupportsShouldProcess=$true)]
[OutputType([bool])]
param(
[Parameter(Mandatory=$true)]
[string]
# The identity of the principal whose privileges to test.
$Identity,
[AllowEmptyCollection()]
[string[]]
# The user's expected/desired privileges.
$Privilege = @(),
[ValidateSet('Present','Absent')]
[string]
# Should the user exist or not exist?
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$resource = Get-TargetResource -Identity $Identity -Privilege $Privilege
$privilegeMissing = $resource.Ensure -eq 'Absent'
if( $Ensure -eq 'Absent' )
{
$absent = $resource.Privilege.Length -eq 0
if( $absent )
{
Write-Verbose ('Identity ''{0}'' has no privileges' -f $Identity)
return $true
}
Write-Verbose ('Identity ''{0}'' has privilege(s) {1}' -f $Identity,($resource.Privilege -join ','))
return $false
}
if( $privilegeMissing )
{
$msgParts = @()
$extraPrivileges = $resource.Privilege | Where-Object { $Privilege -notcontains $_ }
if( $extraPrivileges )
{
$msgParts += 'extra privilege(s): {0}' -f ($extraPrivileges -join ',')
}
$missingPrivileges = $Privilege | Where-Object { $resource.Privilege -notcontains $_ }
if( $missingPrivileges )
{
$msgParts += 'missing privilege(s): {0}' -f ($missingPrivileges -join ',')
}
Write-Verbose ('Identity ''{0}'' {1}' -f $Identity,($msgParts -join '; '))
return $false
}
return $true
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
& (Join-Path -Path $PSScriptRoot -ChildPath '..\Initialize-CarbonDscResource.ps1' -Resolve)
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([hashtable])]
param(
[Parameter(Mandatory=$true)]
[ValidateLength(1,238)]
[Alias('TaskName')]
[string]
# The name of the scheduled task to return. Wildcards supported. This must be the *full task name*, i.e. the task's path/location and its name.
$Name,
[string]
# Install the task from this XML.
$TaskXml,
[Management.Automation.PSCredential]
# The principal the task should run as. Use `Principal` parameter to run as a built-in security principal. Required if `Interactive` or `NoPassword` switches are used.
$TaskCredential,
[ValidateSet('Present','Absent')]
[string]
# If `Present`, the service is installed/updated. If `Absent`, the service is removed.
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$resource = @{
Name = $Name;
TaskXml = '';
TaskCredential = $null;
Ensure = 'Absent';
}
if( (Test-ScheduledTask -Name $Name) )
{
$task = Get-ScheduledTask -Name $Name
$resource.TaskCredential = $task.RunAsUser
$resource.TaskXml = schtasks.exe /query /xml /tn $Name | Where-Object { $_ }
$resource.TaskXml = $resource.TaskXml -join ([Environment]::NewLine)
$resource.Ensure = 'Present'
}
return $resource
}
function Set-TargetResource
{
<#
.SYNOPSIS
DSC resource for configuring scheduled tasks.
.DESCRIPTION
The `Carbon_ScheduledTask` resource configures scheduled tasks using `schtasks.exe` with [Task Scheduler XML](http://msdn.microsoft.com/en-us/library/windows/desktop/aa383609.aspx).
The task is installed when the `Ensure` property is set to `Present`. If the task already exists, and the XML of the current task doesn't match the XML passed in, the task is deleted, and a new task is created in its place. The XML comparison is pretty dumb: it compares the XML document(s) as a giant string, not element by element. This means if your XML doesn't order elements in the same way as `schtasks.exe /query /xml`, then your task will always be deleted and re-created. This may or may not be a problem for you.
`Carbon_ScheduledTask` is new in Carbon 2.0.
.LINK
Get-ScheduledTask
.LINK
Install-ScheduledTask
.LINK
Test-ScheduledTask
.LINK
Uninstall-ScheduledTask
.LINK
http://technet.microsoft.com/en-us/library/cc725744.aspx#BKMK_create
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/aa383609.aspx
.EXAMPLE
>
Demonstrates how to install a new or update an existing scheduled task that runs as a built-in user. The user's SID should be declared in the task XML file.
Carbon_ScheduledTask InstallScheduledTask
{
Name = 'ClearApplicationCache';
TaskXml = (Get-Content -Path $clearApplicationCacheTaskPath.xml -Raw);
}
.EXAMPLE
>
Demonstrates how to install a new or update an existing scheduled task that runs as a custom user.
Carbon_ScheduledTask InstallScheduledTask
{
Name = 'ClearApplicationCache';
TaskXml = (Get-Content -Path $clearApplicationCacheTaskPath.xml -Raw);
TaskCredential = (Get-Credential 'runasuser');
}
.EXAMPLE
>
Demonstrates how to remove a scheduled task.
Carbon_ScheduledTask InstallScheduledTask
{
Name = 'ClearApplicationCache';
Ensure = 'Absent';
}
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[ValidateLength(1,238)]
[Alias('TaskName')]
[string]
# The name of the scheduled task to return. Wildcards supported. This must be the *full task name*, i.e. the task's path/location and its name.
$Name,
[string]
# Install the task from this XML.
$TaskXml,
[Management.Automation.PSCredential]
# The principal the task should run as. Use `Principal` parameter to run as a built-in security principal. Required if `Interactive` or `NoPassword` switches are used.
$TaskCredential,
[ValidateSet('Present','Absent')]
[string]
# If `Present`, the service is installed/updated. If `Absent`, the service is removed.
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$PSBoundParameters.Remove('Ensure')
if( $Ensure -eq 'Present' )
{
$installParams = @{ }
if( (Test-ScheduledTask -Name $Name ) )
{
Write-Verbose ('[{0}] Re-installing' -f $Name)
$installParams['Force'] = $true
}
else
{
Write-Verbose ('[{0}] Installing' -f $Name)
}
Install-ScheduledTask @PSBoundParameters @installParams
}
else
{
Write-Verbose ('[{0}] Uninstalling' -f $Name)
Uninstall-ScheduledTask -Name $Name
}
}
function Test-TargetResource
{
[CmdletBinding(SupportsShouldProcess=$true)]
[OutputType([bool])]
param(
[Parameter(Mandatory=$true)]
[ValidateLength(1,238)]
[Alias('TaskName')]
[string]
# The name of the scheduled task to return. Wildcards supported. This must be the *full task name*, i.e. the task's path/location and its name.
$Name,
[string]
# Install the task from this XML.
$TaskXml,
[Management.Automation.PSCredential]
# The principal the task should run as. Use `Principal` parameter to run as a built-in security principal. Required if `Interactive` or `NoPassword` switches are used.
$TaskCredential,
[ValidateSet('Present','Absent')]
[string]
# If `Present`, the task is installed/updated. If `Absent`, the task is removed.
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$resource = Get-TargetResource -Name $Name
if( $Ensure -eq 'Present' )
{
if( $resource.Ensure -eq 'Absent' )
{
Write-Verbose ('[{0}] Desired scheduled task not found' -f $Name)
return $false
}
if( -not $TaskXml )
{
Write-Error ('Property ''TaskXml'' is missing or empty. When creating a scheduled task, the ''TaskXml'' property is required.')
return $true
}
$resourceXml = [xml]$resource.TaskXml
$currentTaskXml = $resourceXml.OuterXml
$desiredTaskXml = ([xml]$TaskXml).OuterXml
if( $currentTaskXml -ne $desiredTaskXml )
{
$differsAt = 0
for( $idx = 0; $idx -lt $desiredTaskXml.Length -and $idx -lt $currentTaskXml.Length; ++$idx )
{
$charEqual = $desiredTaskXml[$idx] -eq $currentTaskXml[$idx]
if( -not $charEqual )
{
$differsAt = $idx
break
}
}
$nameLength = $Name.Length
$linePrefix = ' ' * ($nameLength + 2)
$msgFormat = @'
'@
Write-Verbose ('[{0}] Task XML differs:' -f $Name)
$startIdx = $differsAt - 35
if( $startIdx -lt 0 )
{
$startIdx = 0
}
$shortestLength = $currentTaskXml.Length
if( $desiredTaskXml.Length -lt $shortestLength )
{
$shortestLength = $desiredTaskXml.Length
}
$length = 70
if( $startIdx + $length -ge $shortestLength )
{
$length = $shortestLength - $startIdx
}
Write-Verbose ('{0} Current {1}' -f $linePrefix,$currentTaskXml.Substring($startIdx,$length))
Write-Verbose ('{0} Desired {1}' -f $linePrefix,$desiredTaskXml.Substring($startIdx,$length))
if( $length -eq 70 )
{
Write-Verbose ('{0} -----------------------------------^' -f $linePrefix)
}
return $false
}
else
{
Write-Verbose ('[{0}] Task XML unchanged' -f $Name)
}
if( $TaskCredential -and $resource.TaskCredential -ne $TaskCredential.UserName )
{
Write-Verbose ('[{0}] [TaskCredential] {0} != {1}' -f $Name,$resource.TaskCredential,$TaskCredential.UserName)
return $false
}
return $true
}
else
{
if( $resource.Ensure -eq 'Present' )
{
Write-Verbose ('[{0}] Found' -f $Name)
return $false
}
Write-Verbose ('[{0}] Not found' -f $Name)
return $true
}
}
Export-ModuleMember -Function *
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
& (Join-Path -Path $PSScriptRoot -ChildPath '..\Initialize-CarbonDscResource.ps1' -Resolve)
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([hashtable])]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the service.
$Name,
[string]
# The path to the service.
$Path,
[ValidateSet('Automatic','Manual','Disabled')]
[string]
# The startup type: automatic, manual, or disabled. Default is automatic.
$StartupType,
[Carbon.Service.FailureAction]
# What to do on the service's first failure. Default is to take no action.
$OnFirstFailure,
[Carbon.Service.FailureAction]
# What to do on the service's second failure. Default is to take no action.
$OnSecondFailure,
[Carbon.Service.FailureAction]
# What to do on the service' third failure. Default is to take no action.
$OnThirdFailure,
[int]
# How many seconds after which the failure count is reset to 0.
$ResetFailureCount,
[int]
# How many milliseconds to wait before restarting the service. Default is 60,0000, or 1 minute.
$RestartDelay,
[int]
# How many milliseconds to wait before handling the second failure. Default is 60,000 or 1 minute.
$RebootDelay,
[string[]]
# What other services does this service depend on?
$Dependency,
[string]
# The command to run when a service fails, including path to the command and arguments.
$Command,
[int]
# How many milliseconds to wait before running the failure command. Default is 0, or immediately.
$RunCommandDelay,
[string]
# The service's display names.
$DisplayName,
[string]
# The service's description.
$Description,
[ValidateSet("LocalSystem", "LocalService", "NetworkService")]
[string]
# The system account the service should run as.
$UserName,
[pscredential]
# The credentials of the custom account the service should run as.
$Credential,
[ValidateSet('Present','Absent')]
[string]
# If `Present`, the service is installed/updated. If `Absent`, the service is removed.
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$resource = @{
Name = $Name;
Path = $null;
StartupType = $null;
OnFirstFailure = $null;
OnSecondFailure = $null;
OnThirdFailure = $null;
ResetFailureCount = $null;
RestartDelay = $null;
RebootDelay = $null;
Command = $null;
RunCommandDelay = $null;
Dependency = $null;
DisplayName = $null;
Description = $null;
UserName = $null;
Credential = $null;
Ensure = 'Absent';
}
if( Test-Service -Name $Name )
{
$service = Get-Service -Name $Name
$resource.Path = $service.Path
$resource.StartupType = $service.StartMode
$resource.OnFirstFailure = $service.FirstFailure
$resource.OnSecondFailure = $service.SecondFailure
$resource.OnThirdFailure = $service.ThirdFailure
$resource.ResetFailureCount = $service.ResetPeriod
$resource.RestartDelay = $service.RestartDelay
$resource.RebootDelay = $service.RebootDelay
$resource.Command = $service.FailureProgram
$resource.RunCommandDelay = $service.RunCommandDelay
$resource.DisplayName = $service.DisplayName
$resource.Description = $service.Description
$resource.UserName = $service.UserName
$actualUserName = Resolve-Identity -Name $service.UserName -ErrorAction Ignore
if( $actualUserName )
{
$resource.UserName = $actualUserName.FullName
}
[string[]]$resource.Dependency = $service.ServicesDependedOn | Select-Object -ExpandProperty Name
$resource.Ensure = 'Present'
}
$resource
}
function Set-TargetResource
{
<#
.SYNOPSIS
DSC resource for configuring Windows services.
.DESCRIPTION
The `Carbon_Service` resource configures Windows services, including name, credentials, startup type, state, failure actions, and dependencies.
The service is installed when the `Ensure` property is set to `Present`. If the service already exists, and its configuration doesn't match the properties being set, the service is stopped, its configuration updated, and the service is restarted. Properties not passed are ignored/left as-is.
In addition to installing the service, this resource also grants the service user the logon as a service privilege and execute permissions on the service executable.
The service is uninstalled when the `Ensure` property is set to `Absent`. The service is stopped, then uninstalled.
`Carbon_Service` is new in Carbon 2.0.
.LINK
Grant-Privilege
.LINK
Install-Service
.LINK
Uninstall-Service
.EXAMPLE
>
Demonstrates how to install a service that runs as a custom account and has custom failure actions.
Carbon_Service InstallNoOpService
{
Name = 'CarbonNoOpService';
Path = 'C:\Projects\Carbon\bin\NoOpService.bin';
StartupType = 'Automatic';
Credential = $noOpServiceCreential';
OnFirstFailure = 'RunCommand';
Command = 'example.exe /fail %1%';
RunCommandDelay = 1000;
OnSecondFailure = 'Restart';
RestartDelay = (1000*60*5); # 5 minutes as milliseconds
}
.EXAMPLE
>
Demonstrates how to install a service that runs as a built-in account.
Carbon_Service InstallNoOpService
{
Name = 'CarbonNoOpService';
Path = 'C:\Projects\Carbon\bin\NoOpService.bin';
StartupType = 'Automatic';
UserName = 'LocalService';
}
.EXAMPLE
>
Demonstrates how to remove a service.
Carbon_Service InstallNoOpService
{
Name = 'CarbonNoOpService';
Ensure = 'Absent';
}
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the service.
$Name,
[string]
# The path to the service.
$Path,
[ValidateSet('Automatic','Manual','Disabled')]
[string]
# The startup type: automatic, manual, or disabled. Default is automatic.
$StartupType,
[Carbon.Service.FailureAction]
# What to do on the service's first failure. Default is to take no action.
$OnFirstFailure,
[Carbon.Service.FailureAction]
# What to do on the service's second failure. Default is to take no action.
$OnSecondFailure,
[Carbon.Service.FailureAction]
# What to do on the service' third failure. Default is to take no action.
$OnThirdFailure,
[int]
# How many seconds after which the failure count is reset to 0.
$ResetFailureCount,
[int]
# How many milliseconds to wait before restarting the service. Default is 60,0000, or 1 minute.
$RestartDelay,
[int]
# How many milliseconds to wait before handling the second failure. Default is 60,000 or 1 minute.
$RebootDelay,
[string[]]
# What other services does this service depend on?
$Dependency,
[string]
# The command to run when a service fails, including path to the command and arguments.
$Command,
[int]
# How many milliseconds to wait before running the failure command. Default is 0, or immediately.
$RunCommandDelay,
[string]
# The service's display names.
$DisplayName,
[string]
# The service's description.
$Description,
[ValidateSet("LocalSystem", "LocalService", "NetworkService")]
[string]
# The system account the service should run as.
$UserName,
[pscredential]
# The credentials of the custom account the service should run as.
$Credential,
[ValidateSet('Present','Absent')]
[string]
# If `Present`, the service is installed/updated. If `Absent`, the service is removed.
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$serviceExists = Test-Service -Name $Name
if( $Ensure -eq 'Absent' )
{
if( $serviceExists )
{
Write-Verbose ('Removing service ''{0}''' -f $Name)
Uninstall-Service -Name $Name
}
return
}
if( -not $Path )
{
Write-Error ('Property ''Path'' mandatory when installing/updating a service.')
return
}
if( $UserName -and $Credential )
{
Write-Error ('UserName and Credential properties are mutually exclusive. Please provide either Credential or UserName, not both.')
return
}
$PSBoundParameters.Remove('Ensure')
if( $serviceExists )
{
Write-Verbose ('Updating service ''{0}''' -f $Name)
}
else
{
Write-Verbose ('Installing service ''{0}''' -f $Name)
}
Install-Service @PSBoundParameters
}
function Test-TargetResource
{
[CmdletBinding(SupportsShouldProcess=$true)]
[OutputType([bool])]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the service.
$Name,
[string]
# The path to the service.
$Path,
[ValidateSet('Automatic','Manual','Disabled')]
[string]
# The startup type: automatic, manual, or disabled. Default is automatic.
$StartupType,
[Carbon.Service.FailureAction]
# What to do on the service's first failure. Default is to take no action.
$OnFirstFailure,
[Carbon.Service.FailureAction]
# What to do on the service's second failure. Default is to take no action.
$OnSecondFailure,
[Carbon.Service.FailureAction]
# What to do on the service' third failure. Default is to take no action.
$OnThirdFailure,
[int]
# How many seconds after which the failure count is reset to 0.
$ResetFailureCount,
[int]
# How many milliseconds to wait before restarting the service. Default is 60,0000, or 1 minute.
$RestartDelay,
[int]
# How many milliseconds to wait before handling the second failure. Default is 60,000 or 1 minute.
$RebootDelay,
[string[]]
# What other services does this service depend on?
$Dependency,
[string]
# The command to run when a service fails, including path to the command and arguments.
$Command,
[int]
# How many milliseconds to wait before running the failure command. Default is 0, or immediately.
$RunCommandDelay,
[string]
# The service's display names.
$DisplayName,
[string]
# The service's description.
$Description,
[ValidateSet("LocalSystem", "LocalService", "NetworkService")]
[string]
# The system account the service should run as.
$UserName,
[pscredential]
# The custom account the service should run as.
$Credential,
[ValidateSet('Present','Absent')]
[string]
# If `Present`, the service is installed/updated. If `Absent`, the service is removed.
$Ensure = 'Present'
)
Set-StrictMode -Version 'Latest'
$resource = Get-TargetResource -Name $Name
if( $Ensure -eq 'Absent' )
{
if( $resource.Ensure -eq 'Absent' )
{
return $true
}
Write-Verbose ('Service ''{0}'' found.' -f $Name)
return $false
}
if( $resource.Ensure -eq 'Absent' )
{
Write-Verbose ('Service ''{0}'' not found.' -f $Name)
return $false
}
if( $PSBoundParameters.ContainsKey( 'UserName' ) )
{
$identity = Resolve-Identity -Name $UserName
if( $identity )
{
$PSBoundParameters['UserName'] = $identity.FullName
}
}
if( $resource.ContainsKey('Credential') )
{
[void]$resource.Remove('Credential')
}
if( $PSBoundParameters.ContainsKey('Credential') )
{
[void]$PSBoundParameters.Remove('Credential')
$identity = Resolve-Identity -Name $Credential.UserName -ErrorAction Ignore
if( $identity )
{
$PSBoundParameters.UserName = $identity.FullName
}
}
return Test-DscTargetResource -TargetResource $resource -DesiredResource $PSBoundParameters -Target ('Service ''{0}''' -f $Name)
}
<#
.SYNOPSIS
Configures PowerShell so that Carbon's DSC resources can use Carbon functions/commands.
#>
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[CmdletBinding()]
param(
)
#Requires -Version 4
Set-StrictMode -Version 'Latest'
Write-Verbose ('Checking if Carbon module loaded.')
if( -not (Get-Module -Name 'Carbon') )
{
Write-Verbose ('Loading Carbon module.')
Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\Carbon.psd1' -Resolve) -Global
}
TOPIC
about_Carbon
SHORT DESCRIPTION
Carbon is a PowerShell module for automating the configuration of computers
running Windows 7, 8, 2008, and 2012. It can configure and manage:
* Local users and groups
* IIS websites, virtual directories, and applications
* File system, registry, and certificate permissions
* Certificates
* Privileges
* Services
* Encryption
* Junctions
* Hosts file
* INI files
* Performance counters
* Shares
* .NET connection strings and app settings
* And much more!
All functions are designed to be idempotent: when run multiple times with the
same arguments, your system will be in the same state without failing or producing
errors.
SYSTEM REQUIREMENTS
PowerShell 4.0/5.0 and .NET Framework 4.5
Windows 7, 8, 2008, or 2012.
INSTALLATION
See the `about_Carbon_Installation` help topic for installation instructions.
SUPPORT
See the `about_Carbon_Support` help topic for ways to ask questions about using
Carbon.
OVERVIEW
Only PowerShell [approved verbs](http://msdn.microsoft.com/en-us/library/windows/desktop/ms714428.aspx)
are used for command names. Carbon assigns special meaning to these verbs:
* Format: Escape (e.g. `Format-ADSearchFilterValue`).
* Install: Create a resource if it doesn't exist. If it does exist, update its
configuration to your desired state (e.g. `Install-User`, `Install-IisWebsite`,
etc.).
* Split: Parse (e.g. Split-Ini)
* Uninstall: Remove a resource if it exists. If it doesn't exist, do nothing.
Carbon has no dependencies and is designed to work on a computer running a fresh
install of Windows. Some functions do interact with some Windows features. If those
features aren't installed, you'll get errors.
Carbon has an automated test suite that runs after every change on a computer
running Windows 2012 R2. Before release, the test suite is run automatically on a
computer running Windows 7 and PowerShell 5. No releases are made unless all tests
pass.
VERSIONING
Carbon uses [semantic versioning](http://semver.org/). We use our version number
to communicate how Carbon changes from the last version. Carbon version numbers have
the form Major.Minor.Patch.
When upgrading to a new version, if:
* Just the patch number has changed (e.g. 1.5.0 -> 1.5.1) then we've only fixed bugs
in a 100% backwards-compatible way. You should feel comfortable upgrading with no
or limited testing.
* The Minor version has changed (e.g. 1.8.0 -> 1.9.0), then we've only fixed bugs or
introduced new functionality in a 100% backwards-compatible way. Again, you should
feel comfortable upgrading with light to limited testing.
When upgrading to a new minor version, always upgrade to the minor version with the
highest patch number.
* The Major version has changed (e.g. 1.9.0 -> 2.0.0), then we've broken
compatibility with previous versions of Carbon. You should carefully review the
release notes and update your code to work with the new version. You'll need to do
a thorough test of any changes to ensure your scripts still work.
SEE ALSO
http://get-carbon.org
https://bitbucket.org/splatteredbits/carbon
about_Carbon_Installation
about_Carbon_Support
about_Carbon_Extended_Type_Data
about_Carbon_2.0
about_Carbon_Contributing
http://semver.org
TOPIC
about_Carbon_2.0
SHORT DESCRIPTION
Describes changes included in Carbon 2.0.
LONG DESCRIPTION
Carbon version 2.0 is a *huge* release, with lots of new enhancements. We hope you
like them. Carbon 2.0 now requires PowerShell 4, so it is not
backwards-compatabile with Carbon 1.x. Because of this, we made some additional
backwards-incompatible changes. See the `Upgrade Instructions` section for things
to look out for.
If you're upgrading from a previous 2.0 alpha release, you'll want to review the
changes since your alpha version (found after the *Upgrade Instructions* section).
We improved backwards-compatability with Carbon 1.x since the last alpha release,
but that broke compatability with the alphas.
UPGRADE INSTRUCTIONS
Make sure you're running PowerShell 4.
`Install-Certificate`'s parameters have changed:
* Remove the `Exportable` switch from any usages of `Install-Certificate` when
installing from an `X509Certificate2` *object*, since that switch only gets used
when installing a certificate from a file.
Some functions now return different objects and/or the objects returned have
changed:
* Use the `Sid` property on objects returned by `Test-Identity` when using the
`PassThru` switch: it now returns a `Carbon.Identity` object if the identity
exists *and* you use the `-PassThru` switch, e.g. `Test-Identity -Name $userName
-PassThru | Select-Object -Expand 'Sid'`.
* Update usages of `Carbon.Computer.ProgramInstallInfo`'s `Version` property
(returned by `Get-ProgramInstallInfo`). It was an `int` and is now a
[Version](http://msdn.microsoft.com/en-us/library/y0hf9t2e.aspx) object.
The Carbon assembly was re-organized. If you were reaching into `Carbon.dll`
(***NOT RECOMMENDED***), you'll want to:
* Rename usages of `[Carbon.AdvApi32]` class to `[Carbon.Service.ServiceSecurity]`.
* Rename usages of `[Carbon.Lsa]` class to `[Carbon.Security.Privilege]`.
* Rename usages of `[Carbon.Win32]` class to `[Carbon.FileSystem.Path]`.
* Rename usages of `[Carbon.HandleInfo]` class to `[Carbon.Win32.HandleInfo]`.
* Remove usages of `[Carbon.Lsa]::LookupPrivilegeValue` class method. It was
incorrectly exposed as a public method.
* Remove usages of `[Carbon.Kernel32]::LocalFree` class method. It was
incorrectly exposed as a public method.
The following commands no longer return the stdout output from the console
applications each one calls. To see the old output, use the `-Verbose` switch.
Remove any usage of the output you were processing.
* All IIS functions.
* `Disable-FirewallStatefulFtp`
* `Enable-FirewallStatefulFtp`
* `Install-Service`
* `Install-SmbShare`
* `Remove-SslCertificateBinding`
* `Set-SslCertificateBinding`
The following functions' internal behavior has changed. This may or may not impact
you.
* `Grant-Permission` now only grants permissions on an object if those
permissions aren't present. To preserve previous behavior, add the `-Force`
switch to all `Grant-Permission` usages.
* `Grant-Permission` now writes an error if you don't have access to a private
key. Previously, it would skip the key without any messages.
* `Install-Msi` (fka `Invoke-WindowsInstaller`) now only installs the MSI if it
isn't already installed. To preserve the previous behavior and always install,
add the `-Force` switch to all `Invoke-WindowsInstaller`\`Install-Msi` usages.
* All IIS functions were re-written to use the `Microsoft.Web.Administration` API
instead of `appcmd.exe`.
* `Install-IisWebsite` no longer deletes and re-creates websites. If a website
exists, it updates its configuration to match parameters passed in. To preserve
previous behavior and delete the website before installing, use the `-Force`
switch.
* `Install-IisVirtualDirectory` no longer deletes and re-creates virtual
directories. If a virtual directory exists, its configuration is updated in
place. To preserve previous behavior and delete the virtual directory before
installing, use the `Force` switch.
* `Install-FileShare` (fka `Install-SmbShare`) no longer deletes and re-creates
the share, instead it modifies existing shares in place. To preserve previous
behavior and delete existing shares before re-creating, use the `Force` switch.
We've added parameter validation to some functions. This shouldn't impact
anybody, since if you were passing data that breaks this new validation, the
function wouldn't have worked even in previous versions of Carbon.
* Ensure that all thumbprints passed to `Set-SslCertificateBinding` are valid (40
character hex strings), since it now validates thumbprints.
* Check that all IP addresses passed to `Set-HostsEntry` are valid IP v4 or v6
addresses. `Set-HostsEntry`'s IPAddress parameter is now a
`System.Net.IPAddress` object. Previously it was a string validated with a
regular expression, so you *should* be OK.
BUG FIXES
* Carbon's `System.ServiceProcess.ServiceController` extended type data causes
errors when PowerShell formats `System.ServiceProcess.ServiceController` objects
that represent services on remote computers.
* `Compress-Item` doesn't remove handled errors from global error array.
* `Grant-Permission` fails with an unhelpful error message if it is unable to get
the ACL on a private key.
* `Install-Msi` didn't properly detect when installation failed.
* `Install-ScheduledTask` fails under PowerShell 5 to create a scheduled task to
run on Sunday.
* `Install-Service`:
* No longer writes a warning about being unable to stop an already stopped
service (fixes [issue #158](https://bitbucket.org/splatteredbits/carbon/issues/158/install-service-extraneous-warning-about)).
* Starting the service now respects caller's error action preference. Before,
`Start-Service` would write an error even if somone called `Install-Service`
with an `Ignore` or `SilentlyContinue` error action preference.
* `Set-EnvironmentVariable` fails to set process-level environment variable.
* `Set-HostsEntry` fails to preserve whitespace if existing lines end with a
comment/description. Thanks to [Konstantin Ushenin](https://vk.com/kostanew) for
the fix.
GENERAL EHANCEMENTS
* Carbon now requires PowerShell 4.
* `Import-Carbon.ps1` is more intelligent about when it tries to re-load Carbon.
It will force a re-import of Carbon if any of Carbon's files have changed or the
version has changed.
* Added new `FileIndex`, `LinkCount`, and `VolumeSerialNumber` extended type data
on `System.IO.FileInfo` objects for getting a file's index, its hard link count,
and volume serial number, respectively.
* The product version of the Carbon assembly now includes pre-release version
information, as defined by the [Semantic Versioning
specification](http://semver.org). To get this version, run `Get-Item Carbon.dll |
Select-Object -ExpandProperty 'VersionInfo' | Select-Object -ExpandProperty
'ProductVersion'`.
* The Carbon NuGet package now supports installing and uninstalling under
Chocolatey.
* All IIS functions were re-written to use the `Microsoft.Web.Administration` API
instead of `appcmd.exe`. As a side effect, they no longer return `appcmd.exe`
console output.
* The following functions no longer use `Write-Host`. Instead, they use
`Write-Verbose`:
* `Disable-NtfsCompression`
* `Enable-NtfsCompression`
* `Grant-ComPermission`
* `Grant-Permission`
* `Install-Service`
* `Remove-SslCertificateBinding`
* `Revoke-ComPermission`
* Created default, table-based display formats for
`System.DirectoryServices.AccountManagement.UserPrincipal`,
`System.DirectoryServices.AccountManagement.GroupPrincipal`,
`Microsoft.Web.Administration.ApplicationPool`,
`Microsoft.Web.Administration.Site`, and
`Microsoft.Web.Administration.Application` objects.
NEW FUNCTIONS
* `Clear-DscLocalResourceCache` clears the local LCM's DSC resource. This makes
developing resources easier.
* `Clear-MofAuthoringMetadata` removes authoring metadata from .mof files.
* `Copy-DscResource` copies DSC resources (ZIP files, MSI archives, MOF files,
etc.), including timestamps, checksums, and copying only changed files.
* `ConvertTo-SecurityIdentifer` converts a binary, string, or
`System.Security.Principal.SecurityIdentifier` object into a
`System.Security.Principal.SecurityIdentifier` object.
* `Get-DscError` gets any DSC errors that were written to a computer's DSC event
log.
* `Get-DscWinEvent` gets DSC events that were written to a computer's DSC event log.
* `Get-FileSharePermission` gets the sharing permissions on a file/SMB share
(*not* the NTFS file system permissions).
* `Get-FileShare` uses WMI to get `Win32_Share` objects for the file shares
installed on the local computer.
* `Get-Group` gets a local group or all local groups.
* `Get-Msi` reads installer information and properties from an MSI file.
* `Get-PowerShellModuleInstallPath` gets the path where new module's should be
installed. Beginning with PowerShell 4, modules should get installed into
`$env:ProgramFiles\Windows PowerShell\Modules`. Under PowerShell 3, it is
`$PSHome\Modules`. This function returns the correct location for the version of
PowerShell you're using.
* `Get-User` gets a local user or all local users.
* `Initialize-Lcm` configures the DSC Local Configuration Manager on computers,
including installing the private key needed for decrypting credentials.
* `Remove-GroupMember` removes a user/group from a local group. Thanks to [Philip Kluss](https://bitbucket.org/philkloose)
for the contribution.
* `Resolve-Identity` converts a system, local, or domain principal name or a SID
(as a `SecurityIdentifer`, string SDDL, or byte array) into its canonical
representation and includes extended identity information: domain, type, and SID.
* `Start-DscPullConfiguration` starts a configuration check on a computer that is
configured to use the PULL refresh mode.
* `Test-DscTargetResource` compares target resource with desired resource. Helpful
when writing `Test-TargetResource` functions.
* `Test-Group` checks if a *local* group exists.
* `Test-FileShare` uses WMI to check if a file/SMB share exists on the local
computer.
* `Test-TypeDataMember` tests if a type has an extended type member defined.
* `Uninstall-FileShare` uninstalls/removes a file share, if it exists.
* `Write-DscError` writes DSC `ErrorLogRecord` objects as errors.
NEW DSC RESOURCES
* `Carbon_EnvironmentVariable` creates/removes machine-level environment variables.
* `Carbon_FirewallRule` configures firewall rules.
* `Carbon_IniFile` manages the contents of INI files.
* `Carbon_Permission` configures file, directory, registry, and certificate
permissions.
* `Carbon_Privilege` configures an identity's privileges.
* `Carbon_ScheduledTask` configures scheduled tasks with `schtasks.exe`.
* `Carbon_Service` configures Windows services.
ADDED PASSTHRU PARAMETERS
Added a `PassThru` switch to the following functions, which will return objects of
the given type:
* `Grant-ComPermission`: `Carbon.Security.ComAccessRule`, representing the granted
permission.
* `Grant-Permission`: `System.Security.AccessControl.AccessRule`, representing the
granted permission.
* `Install-Group`: `System.DirectoryServices.AccountManagement.GroupPrincipal`,
representing the group.
* `Install-IisApplication`: `Microsoft.Web.Administration.Application`,
representing the application.
* `Install-IisWebsite`: `Microsoft.Web.Administration.Site`, representing the
website.
* `Install-Junction`: `System.IO.DirectoryInfo`, representing new target
directories and any new/updated junctions.
* `Install-Service`: `System.ServiceProcess.ServiceController`, representing the
service.
* `Install-User`: `System.DirectoryServices.AccountManagement.UserPrincipal`,
representing the user.
* `Set-SslCertificateBinding`: `Carbon.Certificates.SslCertificateBinding`,
representing the configured binding.
NO MORE CONSOLE OUTPUT
The following functions no longer return the console output of the program each one
runs. Instead, the output is written to the verbose stream (i.e. use the `-Verbose`
switch to see it).
* `Disable-FirewallStatefulFtp`
* `Enable-FirewallStatefulFtp`
* `Install-Service`
* `Remove-SslCertificateBinding`
* `Set-SslCertificateBinding`
OBSOLETE FUNCTIONS AND PARAMETERS
The following functions are now obsolete. Please don't use them and stop using them
if you are. They will be removed from a future major version of Carbon. You'll get
warnings if you use them.
* `Complete-Job`: It's total crap. Use PowerShell's `Wait-Job` cmdlet instead.
* `Invoke-AppCmd`: Switch to Carbon's IIS functions, or use
`Get-IisConfigurationSection` to get `ConfigurationElement` objects from the
`Microsoft.Web.Administration` API that you can modify.
* `Resolve-NetPath`: Switch to something else. Carbon doesn't use `net.exe` anymore.
The following functions now have obsolete parameters, which will be removed from a
future major version of Carbon. You'll get warnings if you use them.
* `Install-IisAppPool's` `UserName` and `Password` parameters. Use the new
`Credential` parameter instead.
* `Install-Msi's` `Quiet` switch. `Install-Msi` always installs in quiet mode.
Please remove usages.
* `Install-Service's` `Password` parameter. Use the new `Credential` parameter
instead.
* `Install-User's` `UserName` and `Password` parameters. Use the new `Credential`
parameter instead.
RENAMED FUNCTIONS
The following functions were renamed, but with backwards-compatible aliases in
place, so you shouldn't have to change any code.
* `Invoke-WindowsInstaller` -> `Install-Msi`
* `Install-SmbShare` -> `Install-FileShare`
SWITCH TO SYSTEM.DIRECTORYSERVICES.ACCOUNTMANAGEMENT API FOR USER/GROUP MANAGEMENT
The following functions were re-written to use the
`System.DirectoryServices.AccountManagement` API, introduced in .NET 3.5.
* `Add-GroupMember`
* `Install-Group`
* `Install-User`
* `Test-User`
* `Uninstall-User`
MISCELLANEOUS CHANGES
* `Get-IisAppPool`
* Now return all application pools installed on the local computer when called
with no parameters.
* Added a default table format for
`Microsoft.Web.Administration.ApplicationPool` objects.
* `Get-ProgramInstallInfo`
* Return object's `Version` property changed from an `int` to a
[Version](http://msdn.microsoft.com/en-us/library/y0hf9t2e.aspx) object.
* Return object's now have `ProductCode` and `User` properties. If a program
doesn't have a product code, it is set to `[Guid]::Empty`. The `User` property
is only set for per-user software installs.
* `Get-ServiceConfiguration` now supports services from remote computers.
* `Grant-Permission` now only grants permissions on an object if those permissions
aren't present. To preserve previous behavior, add the `-Force` switch to all
`Grant-Permission` usages.
* `Install-Certificate's` `Exportable` switch is now only allowed when installing
a certificate from a file. Previously, you could supply the switch when installing
from an X509Certificate2 object but it was ignored.
* `Install-Group's` `Members` parameter renamed to `Member` (with
backwards-compatible alias).
* Added `Credential` parameter to `Install-IisAppPool` for increased security and
to follow PowerShell guidelines.
* `Install-IisVirtualDirectory` no longer deletes and re-creates existing virtual
directories, but modifies existing virtual directories in place.
* `Install-IisWebsite`
* Added `SiteID` parameter tfor setting a website's IIS ID.
* No longer deletes and re-creates websites, but modifies existing websites in
place. This may or may not be a breaking change in your environment.
* `Install-Msi`
* `Path` parameter now supports wildcards.
* Now only installs an MSI if it isn't already installed. To preserve the
previous behavior and always install, add the `-Force` switch to all
`Invoke-WindowsInstaller`\`Install-Msi` usages.
* `Install-Service`
* Now supports service startup parameters/arguments via the `ArgumentList`
parameter.
* Improved error handling and messages. It now uses `net helpmsg` to get
helpful error messages based on sc.exe exit codes.
* Added `Credential` parameter for increased security and to follow PowerShell
guidelines.
* Added `Description` parameter for setting a service's description.
* Added `DisplayName` parameter for setting a service's display name.
* `Install-FileShare` (fka `Install-SmbShare`):
* Re-written to use WMI isntead of `net.exe`, so it no longer returns any
console output.
* Modifies existing shares in place, instead of deleting and re-creating,
*unless* the share's path changes. Changing a share's path requires the old
share to be deleted and a new one created.
* `Install-User`
* Added `PasswordExpires` switch for creating accounts with passwords that
expire.
* Added `UserCannotChangePassword` to prevent user from changing his password.
* `Remove-SslCertificateBinding` has better error handling.
* Added `SID` parameter to `Resolve-IdentityName` to resolve a SID into its
identity name.
* `Set-HostsEntry's` `IPAddress` parameter is now a `System.Net.IPAddress` object.
It used to be a string validated with a regular expression.
* `Test-Identity` now returns a `Carbon.Identity` object if the identity exists
*and* you use the `-PassThru` switch. It used to return the identity's SID. Update
scripts to use the `FullName` property to get the old return value, e.g.
`Test-Identity -Name $userName -PassThru | Select-Object -Expand 'FullName'`.
* `Test-OSIs32Bit` now uses the Environment class's new
[Is64BitOperatingSystem](http://msdn.microsoft.com/en-us/library/system.environment.is64bitoperatingsystem.aspx) property.
* `Test-OSIs64Bit` now uses the Environment class's new
[Is64BitOperatingSystem](http://msdn.microsoft.com/en-us/library/system.environment.is64bitoperatingsystem.aspx) property.
* `Test-PowerShellIs32Bit` now uses the `Environment` class's new
[Is64BitProcess](http://msdn.microsoft.com/en-us/library/system.environment.is64bitprocess.aspx) property.
* `Test-PowerShellIs64Bit` now uses the `Environment` class's new
[Is64BitProcess](http://msdn.microsoft.com/en-us/library/system.environment.is64bitprocess.aspx) property.
* `Uninstall-ScheduledTask` now retries when un-installing a task fails with "The
function attempted to use a name that is reserved for use by another transaction."
error.
* `Unprotect-String`
* Added `AsSecureString` switch, which will return a secure string instead of a
normal string.
* The `Password` parameter now accepts `SecureString` values.
* `Initialize-Lcm`
* Added support for PowerShell 5: `RefreshIntervalMinutes` default value
changed to from 15 to 30; `RefreshIntervalMinutes` minimum value is now 30;
`ConfigurationFrequency`'s minimum value is now 1 (from 2).
TOPIC
about_Carbon_Contributing
SHORT DESCRIPTION
This topic describes how to contribute to the Carbon project.
LONG DESCRIPTION
We welcome your feedback and contributions!
We use Mercurial for source control. To get the Carbon source code onto your computer,
run:
PS> hg clone https://bitbucket.org/splatteredbits/carbon
We belive in Test-Driven Development (TDD)! If you don't, you won't be happy
contributing. Anything you want to submit back to the project must have good tests.
If not, it will take longer to accept your contribution, because we'll have to take
time to write tests. TDD enables us to release new versions of Carbon as soon changes
are committed, pushed, and the tests pass. If the code is ready and works, we want to
release it. No waiting!
Blade is our testing framework. It uses NUnit-inspired assertions, e.g. Assert-True,
Assert-Equal, etc. See http://bitbucket.org/splatteredbits/blade for more information.
To run Carbon's tests (the full suite takes about 45 minutes), run this command in the
root of your Carbon working directory:
PS> .\Invoke-CarbonTest.ps1 -Path .\Test
Tests should always clean-up after themselves and strive to leave an operating system
in the exact state it was in before the test fixture ran.
Unfortunately, we only have the resources to run our tests on a 64-bit Windows 2012 R2
and 7 computer. Any donations to the project would be used to purchase licenses and
hosting for running our tests on 32-bit and 64-bit versions of Windows 7, Windows
2008 R2, and Windows 2012 R2.
Carbon uses semantic versioning (see http://semver.org/). Carbon version numbers
take the form X.Y.Z: X is the major version, Y is the minor version, and Z is the
patch version. The patch version is incremented when backwards-compatible bug
fixes are made. You should feel comfortable rolling out a new patch version
quickly, with limited testing. The minor version is incremented when new,
backwards-compatible changes are introduced, or existing functions are deprecated.
You'll probably want to review the release notes and test those bits that changed
since the last release. The major version is incremented when
backwards-incompatible changes are made. In this case, you'll need to do thorough
testing, and upgrade your scripts to use new functionality.
STYLE GUIDE
We use spaces for indenting. Each level of indent (i.e. "tab") should be four spaces.
This is default in the PowerShell ISE.
Use camel-casing for all function names, including abbreviations three letters or
longer, e.g. Install-Msmq, Install-IisWebsite. Capitalize all letters in one or two
letter abbreviations, e.g. Test-OSIs32Bit.
All function parameter and module variables names must be capitalized, e.g. `$Path`,
`$Name`, etc. All variable names should be lowercase, e.g. `$result`, `$csprojXml`.
Variables that contain a path should end in `Path`, e.g. $csprojPath, $websitePath.
*Always* use an [approved PowerShell verb](http://msdn.microsoft.com/en-us/library/windows/desktop/ms714428.aspx).
If possible, use an [approved PowerShell parameter name](http://msdn.microsoft.com/en-us/library/windows/desktop/dd878352(v=vs.85).aspx).
Use a prefix for all functions that manage a common area of Windows, e.g. Iis for all
IIS-related functions, Msmq for MSMQ-related functions, etc.
All functions must have synopsis, description, and example documentation.
SEE ALSO
https://bitbucket.org/splatteredbits/carbon
https://bitbucket.org/splatteredbits/blade
http://mercurial.selenic.com
TOPIC
about_Carbon_Extended_Type_Data
SHORT DESCRIPTION
Explains all the extended type data Carbon adds to native .NET objects.
LONG DESCRIPTION
The extended type data that Carbon adds are outlined below.
## Microsoft.Web.Administration.Site
* `[string] PhysicalPath { get; }`: the website's physical path (i.e. web root).
## Microsoft.Web.Administration.Application
* `[string] PhysicalPath`: the application's phyiscal path (i.e. web root).
## System.Diagnostics.Process
* `[int] ParentProcessID { get; }`: the ID of the parent process (i.e. the process
that started this process). Uses WMI, so it can be a little slow.
## System.DirectoryServices.AccountManagement.Principal
* `[string] ConnectedServer { get; }`: the server the principal came from. This
information is normally available as `$principal.Context.ConnectedServer`. I'm
lazy so added this member.
## System.IO.DirectoryInfo
* `[bool] IsJunction { get; }`: returns `$true` if the directory is a junction,
`$false` otherwise. Uses the `DirectoryInfo`'s `Attributes` properties to make
this determination.
* `[string] TargetPath { get; }`: if the `DirectoryInfo` represents a junction,
returns the junction's target path (i.e. the path it points to).
## System.IO.FileInfo
* `[uint64] FileIndex { get; }`: the file's index. This is the file's unique
identifier.
* `[uint32] LinkCount { get; }`: the number of links to the file. Each unique file
can be linked to at different paths on the file system.
* `[uint32] VolumeSerialNumber { get; }`: the serial number of the volume the file
is on.
## System.Security.Cryptography.X509Certificates.X509Certificate2
* `[string] IssueTo { get; }`: gets the Issued To information from the certificate.
This is the same information displayed in the Certificates MMC snap-in.
* `[string] IssuedBy { get; }`: gets the Issued By information from the certificate.
This is the same information displayed in the Certificates MMC snap-in.
## System.Security.Cryptography.X509Certificates.X509Store
* `[string] DisplayName { get; }`: gets the name of the store as displayed in the
Certificates MMC snap-in.
* `[Security.Cryptography.X509Certificates.StoreName] StoreName { get; }`: gets the
`Security.Cryptography.X509Certificates.StoreName` enumeration value for a store.
If it doesn't have one, returns an empty string.
## System.ServiceProcess.ServiceController
* `[string] Description { get; }`: gets the service's description.
* `[Carbon.Service.ErrorControl] ErrorControl { get; }`: Specifies how Windows
proceeds if the service fails to load or initialize properly. See
[ErrorControl](https://technet.microsoft.com/en-us/library/Cc963244.aspx) for
an explanation of these values.
* `[string] FailureProgram { get; }`: the program to run if the service fails.
* `[Carbon.Service.FailureAction] FailureAction { get; }`: specifies the action to
take the first time the service fails.
* `[string] LoadOrderGroup { get; }`: the group the service is in when the system
starts services during startup.
* `[string] Path { get; }`: the path, with arguments, of the service's executable.
* `[uint32] RebootDelay { get; }`: the number of milliseconds to wait after the
service fails to restart the computer.
* `[uint32] RebootDelayMinutes { get; }`: the number of minutes (rounded down) to
wait after the service fails to restart the computer. Calculated from the
`RebootDelay`.
* `[string] RebootMessage { get; }`: the message to use when rebooting the system
after the service fails.
* `[uint32] ResetPeriod { get; }`: the number of seconds to wait after a failure
before resetting the failure count back to zero.
* `[uint32] ResetPeriodDays { get; }`: the number of days to wait after a failure
before resetting the failure count back to zero. Calculated from the
`ResetPeriodDays` property, and rounded down to the nearest day.
* `[uint32] RestartDelay { get; }`: the number of milliseconds to wait after the
service fails before attempting to restart it.
* `[uint32] RestartDelayMinutes { get; }`: the number of minutes to wait after the
service fails before attempting to restart it. Calculated from `RestartDelay` and
round down.
* `[uint32] RunCommandDelay { get; }`: the number of milliseconds to wait after a
failure before running the failure command.
* `[uint32] RunCommandDelayMinutes { get; }`: the number of minutes to wait after
a failure before running the failure command.
* `[Carbon.Service.FailureAction] SecondFailure { get; }`: the action to take
when the service fails for the second time.
* `[System.ServiceProcess.ServiceStartMode] StartMode { get; }`: the service's
start mode.
* `[string] TagID { get; }`: the service's tag ID.
* `[Carbon.Service.FailureAction] ThirdFailure { get; }`: the action to take when
the service fails the third time.
* `[string] UserName { get; }`: the name of the user whose credentials the service
runs under.
SEE ALSO
about_Types.ps1xml
TOPIC
about_Carbon_Installation
SHORT DESCRIPTION
Carbon can be installed from a ZIP archive, from the PowerShell gallery, with
Chocolatey, and NuGet.
INSTALL FROM ZIP ARCHIVE
1. [Download the ZIP file from Bitbucket.](https://bitbucket.org/splatteredbits/carbon/downloads)
2. Unblock the zip file (right-click the .zip file, choose Properties, click
"Unblock", then click "OK").
3. Unzip the Carbon module anywhere on your file system.
You can now import module using the `Import-Carbon.ps1` script:
PS> .\Carbon\Import-Carbon.ps1
To make Carbon available so you can run `Import-Module Carbon`, copy the `Carbon`
directory into one of PowerShell's module paths. This command will you a list:
PS> $env:PSModulePath -split ';'
Once you do, you can import Carbon by running:
PS> Import-Module 'Carbon'
INSTALL FROM POWERSHELL GALLERY
To install from the PowerShell Gallery, you must be running PowerShell 5. If so,
run:
PS> Install-Module -Name 'Carbon'
You can now import Carbon by running:
PS> Import-Module 'Carbon'
INSTALL WITH CHOCOLATEY
To install with Chocolatey, you'll need [Chocolatey installed](http://chocolatey.org).
With Chocolatey installed, run:
PS> choco install Carbon
This will install Carbon into one of PowerShell's module paths. You can now import
Carbon by running:
PS> Import-Module 'Carbon'
INSTALL WITH NUGET
To install with NuGet, you'll need [NuGet installed](http://nuget.org). With NuGet
installed, run:
PS> nuget install Carbon
This will create a `Carbon-X.Y.Z` directory in your current directory (or the
output directory you specified with Nuget's `OutputDirectory` parameter). You can
import Carbon from that directory using the `Import-Carbon.ps1 script:
PS> .\Carbon-X.Y.Z\Carbon\Import-Carbon.ps1
Or with PowerShell's `Import-Module` command:
PS> Import-Module '.\Carbon-X.Y.Z\Carbon'
If you want Carbon available so you can run `Import-Module Carbon`, copy the
`Carbon-X.Y.Z\Carbon` directory into one of PowerShell's module paths. This command
will give you a list:
PS> $env:PSModulePath -split ';'
SEE ALSO
http://chocolatey.org
http://www.nuget.org
https://www.powershellgallery.com/
https://bitbucket.org/splatteredbits/carbon/downloads
TOPIC
about_Carbon_Support
SHORT DESCRIPTION
This topic describes how you can get help using Carbon.
OVERVIEW
Remember, Carbon is open-source software, and comes "as is", ***without
warranties or conditions of any kind, either express or implied***. The Carbon
users and developers are volunteering to help you. Please respect their time and
assistance.
CHAT
Carbon has a [Gitter chat room](https://gitter.im/splatteredbits/Carbon/) you can
use to ask questions and get help. The project owner/maintainer usually hangs out
there during business hours, Monday through Friday. He's in the Pacific time zone.
You'll need a [GitHub](https://github.com) account to login and ask questions.
E-MAIL
Carbon has a public mailing list: [[email protected]](mailto:[email protected]). Anyone can ask questions. You do need to subscribe to be part of
the community and answer questions. [Subscribe to the list.](https://groups.google.com/forum/#!forum/carbonps).
REPORTING BUGS AND REQUESTING NEW FEATURES AND ENHANCEMENTS
If you've found a bug or want to request an enhancement, create an issue on the
project's [Bitbucket site](https://bitbucket.org/splatteredbits/carbon/issues?status=new&status=open).
SEE ALSO
https://gitter.im/splatteredbits/Carbon/
[email protected]
https://groups.google.com/forum/#!forum/carbonps
https://bitbucket.org/splatteredbits/carbon/issues?status=new&status=open
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Add-GroupMember
{
<#
.SYNOPSIS
Adds a users or groups to a *local* group.
.DESCRIPTION
You would think it's pretty easy and straight-forward to add users/groups to a local group, but you would be wrong. The quick solution is to use `net localgroup`, but that won't accept user/group names longer than 24 characters. This means you have to use the .NET Directory Services APIs. How do you reliably add both users *and* groups? What if those users are in a domain? What if they're in another domain? What about built-in users? Fortunately, you're brain hasn't exploded.
So, this function adds users and groups to a *local* group.
If the members are already part of the group, nothing happens.
The user running this function must have access to the directory where each principal in the `Member` parameter and the directory where each of the group's current members are located.
.EXAMPLE
Add-GroupMember -Name Administrators -Member EMPIRE\DarthVader,EMPIRE\EmperorPalpatine,REBELS\LSkywalker
Adds Darth Vader, Emperor Palpatine and Luke Skywalker to the local administrators group.
.EXAMPLE
Add-GroupMember -Name TieFighters -Member NetworkService
Adds the local NetworkService account to the local TieFighters group.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The group name.
$Name,
[Parameter(Mandatory=$true)]
[string[]]
# The users/groups to add to a group.
[Alias('Members')]
$Member
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
[DirectoryServices.AccountManagement.GroupPrincipal]$group = Get-Group -Name $Name
if( -not $group )
{
return
}
try
{
foreach( $_member in $Member )
{
$identity = Resolve-Identity -Name $_member
if( -not $identity )
{
continue
}
if( (Test-GroupMember -GroupName $group.Name -Member $_member) )
{
continue
}
Write-Verbose -Message ('[{0}] Members -> {1}' -f $Name,$identity.FullName)
if( -not $PSCmdlet.ShouldProcess(('adding ''{0}'' to local group ''{1}''' -f $identity.FullName, $group.Name), $null, $null) )
{
continue
}
try
{
$identity.AddToLocalGroup( $group.Name )
}
catch
{
Write-Error ('Failed to add ''{0}'' to group ''{1}'': {2}.' -f $identity,$group.Name,$_)
}
}
}
finally
{
$group.Dispose()
}
}
Set-Alias -Name 'Add-GroupMembers' -Value 'Add-GroupMember'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Add-IisDefaultDocument
{
<#
.SYNOPSIS
Adds a default document name to a website.
.DESCRIPTION
If you need a custom default document for your website, this function will add it. The `FileName` argument should be a filename IIS should use for a default document, e.g. home.html.
If the website already has `FileName` in its list of default documents, this function silently returns.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Add-IisDefaultDocument -SiteName MySite -FileName home.html
Adds `home.html` to the list of default documents for the MySite website.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the site where the default document should be added.
$SiteName,
[Parameter(Mandatory=$true)]
[string]
# The default document to add.
$FileName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$section = Get-IisConfigurationSection -SiteName $SiteName -SectionPath 'system.webServer/defaultDocument'
if( -not $section )
{
return
}
[Microsoft.Web.Administration.ConfigurationElementCollection]$files = $section.GetCollection('files')
$defaultDocElement = $files | Where-Object { $_["value"] -eq $FileName }
if( -not $defaultDocElement )
{
Write-IisVerbose $SiteName 'Default Document' '' $FileName
$defaultDocElement = $files.CreateElement('add')
$defaultDocElement["value"] = $FileName
$files.Add( $defaultDocElement )
$section.CommitChanges()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
filter Add-IisServerManagerMember
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
# The object on which the server manager members will be added.
$InputObject,
[Parameter(Mandatory=$true)]
[Microsoft.Web.Administration.ServerManager]
# The server manager object to use as the basis for the new members.
$ServerManager,
[Switch]
# If set, will return the input object.
$PassThru
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$InputObject |
Add-Member -MemberType NoteProperty -Name 'ServerManager' -Value $ServerManager -PassThru |
Add-Member -MemberType ScriptMethod -Name 'CommitChanges' -Value { $this.ServerManager.CommitChanges() }
if( $PassThru )
{
return $InputObject
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Add-TrustedHost
{
<#
.SYNOPSIS
Adds an item to the computer's list of trusted hosts.
.DESCRIPTION
Adds an entry to this computer's list of trusted hosts. If the item already exists, nothing happens.
PowerShell Remoting needs to be turned on for this function to work.
.LINK
Enable-PSRemoting
.EXAMPLE
Add-TrustedHost -Entry example.com
Adds `example.com` to the list of this computer's trusted hosts. If `example.com` is already on the list of trusted hosts, nothing happens.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string[]]
[Alias("Entries")]
# The computer name(s) to add to the trusted hosts
$Entry
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$trustedHosts = @( Get-TrustedHost )
$newEntries = @()
$Entry | ForEach-Object {
if( $trustedHosts -notcontains $_ )
{
$trustedHosts += $_
$newEntries += $_
}
}
if( $pscmdlet.ShouldProcess( "trusted hosts", "adding $( ($newEntries -join ',') )" ) )
{
Set-TrustedHost -Entry $trustedHosts
}
}
Set-Alias -Name 'Add-TrustedHosts' -Value 'Add-TrustedHost'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Assert-AdminPrivilege
{
<#
.SYNOPSIS
Writes an error and returns false if the user doesn't have administrator privileges.
.DESCRIPTION
Many scripts and functions require the user to be running as an administrator. This function checks if the user is running as an administrator or with administrator privileges and writes an error if the user doesn't.
.LINK
Test-AdminPrivilege
.EXAMPLE
Assert-AdminPrivilege
Writes an error that the user doesn't have administrator privileges.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-AdminPrivilege) )
{
Write-Error "You are not currently running with administrative privileges. Please re-start PowerShell as an administrator (right-click the PowerShell application, and choose ""Run as Administrator"")."
return $false
}
return $true
}
Set-Alias -Name 'Assert-AdminPrivileges' -Value 'Assert-AdminPrivilege'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Assert-FirewallConfigurable
{
<#
.SYNOPSIS
Asserts that the Windows firewall is configurable and writes an error if it isn't.
.DESCRIPTION
The Windows firewall can only be configured if it is running. This function checks test if it is running. If it isn't, it writes out an error and returns `False`. If it is running, it returns `True`.
.OUTPUTS
System.Boolean.
.EXAMPLE
Assert-FirewallConfigurable
Returns `True` if the Windows firewall can be configured, `False` if it can't.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( (Get-Service 'Windows Firewall').Status -ne 'Running' )
{
Write-Error "Unable to configure firewall: Windows Firewall service isn't running."
return $false
}
return $true
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Assert-Service
{
<#
.SYNOPSIS
Checks if a service exists, and writes an error if it doesn't.
.DESCRIPTION
Also returns `True` if the service exists, `False` if it doesn't.
.OUTPUTS
System.Boolean.
.LINK
Test-Service
.EXAMPLE
Assert-Service -Name 'Drivetrain'
Writes an error if the `Drivetrain` service doesn't exist.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the service.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Service $Name) )
{
Write-Error ('Service {0} not found.' -f $Name)
return $false
}
return $true
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Assert-WindowsFeatureFunctionsSupported
{
<#
.SYNOPSIS
INTERNAL. DO NOT USE.
.DESCRIPTION
INTERNAL. DO NOT USE.
.EXAMPLE
Assert-WindowsFeatureFunctionsSupported
Writes an error and returns `false` if support for managing functions isn't found.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $windowsFeaturesNotSupported )
{
Write-Warning $supportNotFoundErrorMessage
return $false
}
return $true
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Clear-DscLocalResourceCache
{
<#
.SYNOPSIS
Clears the local DSC resource cache.
.DESCRIPTION
DSC caches resources. This is painful when developing, since you're constantly updating your resources. This function allows you to clear the DSC resource cache on the local computer. What this function really does, is kill the DSC host process running DSC.
`Clear-DscLocalResourceCache` is new in Carbon 2.0.
.EXAMPLE
Clear-DscLocalResourceCache
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Get-WmiObject msft_providers |
Where-Object {$_.provider -like 'dsccore'} |
Select-Object -ExpandProperty HostProcessIdentifier |
ForEach-Object { Get-Process -ID $_ } |
Stop-Process -Force
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Clear-TrustedHost
{
<#
.SYNOPSIS
Removes all entries from PowerShell trusted hosts list.
.DESCRIPTION
The `Add-TrustedHost` function adds new entries to the trusted hosts list. `Set-TrustedHost` sets it to a new list. This function clears out the trusted hosts list completely. After you run it, you won't be able to connect to any computers until you add them to the trusted hosts list.
.LINK
Add-TrustedHost
.LINK
Set-TrustedHost
.EXAMPLE
Clear-TrustedHost
Clears everything from the trusted hosts list.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $pscmdlet.ShouldProcess( 'trusted hosts', 'clear' ) )
{
Set-Item $TrustedHostsPath -Value '' -Force
}
}
Set-Alias -Name 'Clear-TrustedHosts' -Value 'Clear-TrustedHost'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Complete-Job
{
<#
.SYNOPSIS
OBSOLETE. Use PowerShell's `Wait-Job` cmdlet instead. Will be removed in a future major version of Carbon.
.DESCRIPTION
OBSOLETE. Use PowerShell's `Wait-Job` cmdlet instead. Will be removed in a future major version of Carbon.
.EXAMPLE
Get-Job | Wait-Job
Demonstrates that `Complete-Job` is OBSOLETE and you should use PowerShell's `Wait-Job` cmdlet instead.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Management.Automation.Job[]]
# The jobs to complete.
[Alias('Jobs')]
$Job,
[Parameter()]
[int]
# The number of seconds to sleep between job status checks. Default is 1 second.
$IntervalSeconds = 1
)
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Write-Warning ('Complete-Job is obsolete and will be removed in a future major version of Carbon. Use PowerShell''s `Wait-Job` cmdlet instead.')
$errorAction = 'Continue'
$params = $PSBoundParameters
if( $PSBoundParameters.ContainsKey( 'ErrorAction' ) )
{
$errorAction = $PSBoundParameters.ErrorAction
}
trap { Write-Warning "Unhandled error found: $_" }
$numFailed = 0
do
{
Start-Sleep -Seconds $IntervalSeconds
$jobsStillRunning = $false
foreach( $pendingJob in $Job )
{
$currentJob = Get-Job $pendingJob.Id -ErrorAction SilentlyContinue
if( -not $currentJob )
{
Write-Verbose "Job with ID $($pendingJob.Id) doesn't exist."
continue
}
try
{
Write-Verbose "Job $($currentJob.Name) is in the $($currentJob.State) state."
$jobHeader = "# $($currentJob.Name): $($currentJob.State)"
if( $currentJob.State -eq 'Blocked' -or $currentJob.State -eq 'Stopped')
{
Write-Host $jobHeader
Write-Verbose "Stopping job $($currentJob.Name)."
Stop-Job -Job $currentJob
Write-Verbose "Receiving job $($currentJob.Name)."
Receive-Job -Job $currentJob -ErrorAction $errorAction| Write-Host
Write-Verbose "Removing job $($currentJob.Name)."
Remove-Job -Job $currentJob
$numFailed += 1
}
elseif( $currentJob.State -eq 'Completed' -or $currentJob.State -eq 'Failed' )
{
Write-Host $jobHeader
Write-Verbose "Receiving job $($currentJob.Name)."
Receive-Job -Job $currentJob -ErrorAction $errorAction | Write-Host
Write-Verbose "Removing job $($currentJob.Name)."
Remove-Job -Job $currentJob
if( $currentJob.State -eq 'Failed' )
{
$numFailed += 1
}
}
elseif( $currentJob.State -eq 'NotStarted' -or $currentJob.State -eq 'Running' )
{
$jobsStillRunning = $true
}
else
{
Write-Error "Found unknown job state $($currentJob.State)."
}
}
catch
{
Write-Warning "Encountered error handling job $($currentJob.Name)."
Write-Warning $_
}
}
} while( $jobsStillRunning )
return $numFailed
}
Set-Alias -Name 'Complete-Jobs' -Value 'Complete-Job'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Compress-Item
{
<#
.SYNOPSIS
Compresses a file/directory using the `DotNetZip` library.
.DESCRIPTION
You can supply a destination file path, via the `OutFile` parameter. If the file doesn't exist, it is created. If it exists, use the `-Force` parameter to overwrite it.
Each item added to the ZIP file will be added to the root of the file, with a name matching the original file's/directory's name. For example, if adding the file `C:\Projects\Carbon\RELEASE NOTE.txt`, it would get added to the ZIP file as `RELEASE NOTES.txt`.
If you don't supply an output file path, one will be created in the current user's TEMP directory.
A `System.IO.FileInfo` object is returned representing the ZIP file.
Microsoft's DSC Local Configuration Manager is unable to unzip files compressed with the `DotNetZip` library (or the `ZipFile` class in .NET 4.5), so as an alternative, if you specify the `UseShell` switch, the file will be compressed with the Windows COM shell API.
.LINK
https://www.nuget.org/packages/DotNetZip
.LINK
Expand-Item
.LINK
Test-ZipFile
.EXAMPLE
Compress-Item -Path 'C:\Projects\Carbon' -OutFile 'C:\Carbon.zip'
Demonstrates how to create a ZIP file of the `C:\Projects\Carbon` directory.
.EXAMPLE
Get-ChildItem -Path 'C:\Projects\Carbon' | Where-Object { $_.PsIsContainer} | Compress-Item -OutFile 'C:\Projects\Carbon.zip'
Demonstrates how you can pipe items to `Compress-Item` for compressing.
.EXAMPLE
Compress-Item -Path 'C:\Projects\Carbon' -OutFile 'C:\Carbon.zip' -UseShell
Demonstrates how to create a ZIP file with the Windows shell COM APIs instead of the `DotNetZip` library.
#>
[OutputType([IO.FileInfo])]
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[Alias('FullName')]
[string[]]
# The path to the files/directories to compress.
$Path,
[string]
# Path to destination ZIP file. If not provided, a ZIP file will be created in the current user's TEMP directory.
$OutFile,
[Switch]
# Uses the Windows COM shell API to create the zip file instead of the `DotNetZip` library. Microsoft's DSC Local Configuration Manager can't unzip files zipped with `DotNetZip` (or even the .NET 4.5 `ZipFile` class).
$UseShell,
[Switch]
# Overwrites an existing ZIP file.
$Force
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$zipFile = $null
if( $OutFile )
{
$OutFile = Resolve-FullPath -Path $OutFile
if( (Test-Path -Path $OutFile -PathType Leaf) )
{
if( -not $Force )
{
Write-Error ('File ''{0}'' already exists. Use the `-Force` switch to overwrite.' -f $OutFile)
return
}
}
}
else
{
$OutFile = 'Carbon+Compress-Item-{0}.zip' -f ([IO.Path]::GetRandomFileName())
$OutFile = Join-Path -Path $env:TEMP -ChildPath $OutFile
}
if( $UseShell )
{
[byte[]]$data = New-Object byte[] 22
$data[0] = 80
$data[1] = 75
$data[2] = 5
$data[3] = 6
[IO.File]::WriteAllBytes($OutFile, $data)
$shellApp = New-Object -ComObject "Shell.Application"
$copyHereFlags = (
# 0x4 = No dialog
# 0x10 = Responde "Yes to All" to any prompts
# 0x400 = Do not display a user interface if an error occurs
0x4 -bor 0x10 -bor 0x400
)
$zipFile = $shellApp.NameSpace($OutFile)
$zipItemCount = 0
}
else
{
$zipFile = New-Object 'Ionic.Zip.ZipFile'
}
}
process
{
if( -not $zipFile )
{
return
}
$Path | Resolve-Path | Select-Object -ExpandProperty 'ProviderPath' | ForEach-Object {
$zipEntryName = Split-Path -Leaf -Path $_
if( $PSCmdlet.ShouldProcess( $_, ('compress to {0} as {1}' -f $OutFile,$zipEntryName)) )
{
if( $UseShell )
{
[void]$zipFile.CopyHere($_, $copyHereFlags)
$entryCount = Get-ChildItem $_ -Recurse | Measure-Object | Select-Object -ExpandProperty 'Count'
$zipItemCount += $entryCount
}
else
{
if( Test-Path -Path $_ -PathType Container )
{
[void]$zipFile.AddDirectory( $_, $zipEntryName )
}
else
{
[void]$zipFile.AddFile( $_, '.' )
}
}
}
}
}
end
{
if( -not $zipFile )
{
return
}
if( $UseShell )
{
[void][Runtime.InteropServices.Marshal]::ReleaseComObject($zipFile)
[void][Runtime.InteropServices.Marshal]::ReleaseComObject($shellApp)
do
{
try
{
if( [Ionic.Zip.ZipFile]::CheckZip( $OutFile ) )
{
$zipFile = [Ionic.Zip.ZipFile]::Read($OutFile)
$count = $zipFile.Count
$zipFile.Dispose()
if( $zipItemCount -eq $count )
{
Write-Verbose ('Found {0} expected entries in ZIP file ''{1}''.' -f $zipItemCount,$OutFile)
break
}
Write-Verbose ('ZIP file ''{0}'' has {1} entries, but expected {2}. Looks like the Shell API is still writing to it.' -f $OutFile,$count,$zipItemCount)
}
else
{
Write-Verbose ('ZIP file ''{0}'' not valid. Looks like Shell API is still writing to it.' -f $OutFile)
}
}
catch
{
Write-Verbose ('Encountered an exception checking if the COM Shell API has finished creating ZIP file ''{0}'': {1}' -f $OutFile,$_.Exception.Message)
$Global:Error.RemoveAt(0)
}
Start-Sleep -Milliseconds 100
}
while( $true )
}
else
{
if( $PSCmdlet.ShouldProcess( $OutFile, 'saving' ) )
{
$zipFile.Save( $OutFile )
}
$zipFile.Dispose()
}
Get-Item -Path $OutFile
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Convert-SecureStringToString
{
<#
.SYNOPSIS
Converts a secure string into a plain text string.
.DESCRIPTION
Sometimes you just need to convert a secure string into a plain text string. This function does it for you. Yay! Once you do, however, the cat is out of the bag and your password will be *all over memory* and, perhaps, the file system.
.OUTPUTS
System.String.
.EXAMPLE
Convert-SecureStringToString -SecureString $mySuperSecretPasswordIAmAboutToExposeToEveryone
Returns the plain text/decrypted value of the secure string.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Security.SecureString]
# The secure string to convert.
$SecureString
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$stringPtr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
return [Runtime.InteropServices.Marshal]::PtrToStringAuto($stringPtr)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Convert-XmlFile
{
<#
.SYNOPSIS
Transforms an XML document using XDT (XML Document Transformation).
.DESCRIPTION
An XDT file specifies how to change an XML file from a *known* beginning state into a new state. This is usually helpful when deploying IIS websites. Usually, the website's default web.config file won't work in different environments, and needs to be changed during deployment to reflect settings needed for the target environment.
XDT was designed to apply a tranformation against an XML file in a *known* state. **Do not use this method to transform an XML file in-place.** There lies madness, and you will never get that square peg into XDT's round hole. If you *really* want to transform in-place, you're responsible for checking if the source/destination file has already been transformed, and if it hasn't, calling `Convert-XmlFile` to transform to a temporary file, then copying the temporary file onto the source/destination file.
You can load custom transformations. In your XDT XML, use the `xdt:Import` element to import your transformations. In your XDT file:
<?xml version="1.0"?>
<root xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!-- You can also use the "assembly" attribute (PowerShell v3
*only*). In PowerShell v2, you can only use the `path`
attribute.
All classes in `namespace` that inherit from the XDT
`Transform` class are loaded. -->
<xdt:Import path="C:\Projects\Carbon\Lib\ExtraTransforms.dll"
namespace="ExtraTransforms" />
<!-- ...snip... -->
</root>
You also have to pass the path to your custom transformation assembly as a value to the `TransformAssemblyPath` parameter. That's it! (Note: Carbon does *not* ship with any extra transformations.)
When transforming a file, the XDT framework will write warnings and errors to the PowerShell error and warning stream. Informational and debug messages are written to the verbose stream (i.e. use the `Verbose` switch to see all the XDT log messages).
.LINK
http://msdn.microsoft.com/en-us/library/dd465326.aspx
.LINK
http://stackoverflow.com/questions/2915329/advanced-tasks-using-web-config-transformation
.LINK
Set-DotNetConnectionString
.LINK
Set-DotNetAppSetting
.EXAMPLE
Convert-XmlFile -Path ".\web.config" -XdtPath ".\web.debug.config" -Destination '\\webserver\wwwroot\web.config'
Transforms `web.config` with the XDT in `web.debug.config` to a new file at `\\webserver\wwwroot\web.config`.
.EXAMPLE
Convert-XmlFile -Path ".\web.config" -XdtXml "<configuration><connectionStrings><add name=""MyConn"" xdt:Transform=""Insert"" /></connectionStrings></configuration>" -Destination '\\webserver\wwwroot\web.config'
Transforms `web.config` with the given XDT XML to a new file at `\\webserver\wwwroot\web.config`.
.EXAMPLE
Convert-XmlFile -Path ".\web.config" -XdtPath ".\web.debug.config" -Destination '\\webserver\wwwroot\web.config' -Verbose
See that `Verbose` switch? It will show informational/debug messages written by the XDT framework. Very helpful in debugging what XDT framework is doing.
.EXAMPLE
Convert-XmlFile -Path ".\web.config" -XdtPath ".\web.debug.config" -Destination '\\webserver\wwwroot\web.config' -TransformAssemblyPath C:\Projects\CustomTransforms.dll
Shows how to reference a custom transformation assembly. It should also be loaded in your XDT file via the `xdt:Import`.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The path of the XML file to convert.
$Path,
[Parameter(Mandatory=$true,ParameterSetName='ByXdtFile')]
[string]
# The path to the XDT file.
$XdtPath,
[Parameter(Mandatory=$true,ParameterSetName='ByXdtXml')]
[xml]
# The raw XDT XML to use.
$XdtXml,
[Parameter(Mandatory=$true)]
[string]
# The destination XML file's path.
$Destination,
[string[]]
# List of assemblies to load which contain custom transforms.
$TransformAssemblyPath = @(),
[Switch]
# Overwrite the destination file if it exists.
$Force
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Path -Path $Path -PathType Leaf))
{
Write-Error ("Path '{0}' not found." -f $Path)
return
}
if( $PSCmdlet.ParameterSetName -eq 'ByXdtXml' )
{
$xdtPathForInfoMsg = ''
$xdtPathForShouldProcess = 'raw XDT XML'
$XdtPath = 'Carbon_Convert-XmlFile_{0}' -f ([IO.Path]::GetRandomFileName())
$XdtPath = Join-Path $env:TEMP $XdtPath
$xdtXml.Save( $XdtPath )
}
else
{
if( -not (Test-Path -Path $XdtPath -PathType Leaf) )
{
Write-Error ("XdtPath '{0}' not found." -f $XdtPath)
return
}
$XdtPath = Resolve-FullPath -Path $XdtPath
$xdtPathForShouldProcess = $XdtPath
$xdtPathForInfoMsg = 'with ''{0}'' ' -f $XdtPath
}
$Path = Resolve-FullPath -Path $Path
$Destination = Resolve-FullPath -Path $Destination
$TransformAssemblyPath = $TransformAssemblyPath | ForEach-Object { Resolve-FullPath -path $_ }
if( $TransformAssemblyPath )
{
$badPaths = $TransformAssemblyPath | Where-Object { -not (Test-Path -Path $_ -PathType Leaf) }
if( $badPaths )
{
$errorMsg = "TransformAssemblyPath not found:`n * {0}" -f ($badPaths -join "`n * ")
Write-Error -Message $errorMsg -Category ObjectNotFound
return
}
}
if( $Path -eq $Destination )
{
$errorMsg = 'Can''t transform Path {0} onto Destination {1}: Path is the same as Destination. XDT is designed to transform an XML file from a known state to a new XML file. Please supply a new, unique path for the Destination XML file.' -f `
$Path,$Destination
Write-Error -Message $errorMsg -Category InvalidOperation -RecommendedAction 'Set Destination parameter to a unique path.'
return
}
if( -not $Force -and (Test-Path -Path $Destination -PathType Leaf) )
{
$errorMsg = 'Can''t transform ''{0}'': Destination ''{1}'' exists. Use the -Force switch to overwrite.' -f $Path,$Destination
Write-Error $errorMsg -Category InvalidOperation -RecommendedAction 'Use the -Force switch to overwrite.'
return
}
$scriptBlock = {
param(
[Parameter(Position=0)]
[string]
$CarbonBinDir,
[Parameter(Position=1)]
[string]
$Path,
[Parameter(Position=2)]
[string]
$XdtPath,
[Parameter(Position=3)]
[string]
$Destination,
[Parameter(Position=4)]
[string[]]
$TransformAssemblyPath
)
Add-Type -Path (Join-Path $CarbonBinDir "Microsoft.Web.XmlTransform.dll")
Add-Type -Path (Join-Path $CarbonBinDir "Carbon.Xdt.dll")
if( $TransformAssemblyPath )
{
$TransformAssemblyPath | ForEach-Object { Add-Type -Path $_ }
}
function Convert-XmlFile
{
[CmdletBinding()]
param(
[string]
$Path,
[string]
$XdtPath,
[string]
$Destination
)
try
{
$document = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument
$document.PreserveWhitespace = $true
$document.Load($Path)
$logger = New-Object Carbon.Xdt.PSHostUserInterfaceTransformationLogger $PSCmdlet.CommandRuntime
$xmlTransform = New-Object Microsoft.Web.XmlTransform.XmlTransformation $XdtPath,$logger
$success = $xmlTransform.Apply($document)
if($success)
{
$document.Save($Destination)
}
}
finally
{
if( $xmlTransform )
{
$xmlTransform.Dispose()
}
if( $document )
{
$document.Dispose()
}
}
}
$PsBoundParameters.Remove( 'CarbonBinDir' )
$PSBoundParameters.Remove( 'TransformAssemblyPath' )
Convert-XmlFile @PSBoundParameters
}
try
{
if( $PSCmdlet.ShouldProcess( $Path, ('transform with {0} -> {1}' -f $xdtPathForShouldProcess,$Destination) ) )
{
$argumentList = $CarbonBinDir,$Path,$XdtPath,$Destination,$TransformAssemblyPath
if( $PSVersionTable.CLRVersion.Major -ge 4 )
{
Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $argumentList
}
else
{
Invoke-PowerShell -Command $scriptBlock -Args $argumentList -Runtime 'v4.0'
}
}
}
finally
{
if( $PSCmdlet.ParameterSetName -eq 'ByXdtXml' )
{
Remove-Item -Path $XdtPath
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function ConvertFrom-Base64
{
<#
.SYNOPSIS
Converts a base-64 encoded string back into its original string.
.DESCRIPTION
For some reason. .NET makes encoding a string a two-step process. This function makes it a one-step process.
You're actually allowed to pass in `$null` and an empty string. If you do, you'll get `$null` and an empty string back.
.LINK
ConvertTo-Base64
.EXAMPLE
ConvertFrom-Base64 -Value 'RW5jb2RlIG1lLCBwbGVhc2Uh'
Decodes `RW5jb2RlIG1lLCBwbGVhc2Uh` back into its original string.
.EXAMPLE
ConvertFrom-Base64 -Value 'RW5jb2RlIG1lLCBwbGVhc2Uh' -Encoding ([Text.Encoding]::ASCII)
Shows how to specify a custom encoding in case your string isn't in Unicode text encoding.
.EXAMPLE
'RW5jb2RlIG1lIQ==' | ConvertTo-Base64
Shows how you can pipeline input into `ConvertFrom-Base64`.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[AllowNull()]
[AllowEmptyString()]
[string[]]
# The base-64 string to convert.
$Value,
[Text.Encoding]
# The encoding to use. Default is Unicode.
$Encoding = ([Text.Encoding]::Unicode)
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
}
process
{
$Value | ForEach-Object {
if( $_ -eq $null )
{
return $null
}
$bytes = [Convert]::FromBase64String($_)
$Encoding.GetString($bytes)
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function ConvertTo-Base64
{
<#
.SYNOPSIS
Converts a value to base-64 encoding.
.DESCRIPTION
For some reason. .NET makes encoding a string a two-step process. This function makes it a one-step process.
You're actually allowed to pass in `$null` and an empty string. If you do, you'll get `$null` and an empty string back.
.LINK
ConvertFrom-Base64
.EXAMPLE
ConvertTo-Base64 -Value 'Encode me, please!'
Encodes `Encode me, please!` into a base-64 string.
.EXAMPLE
ConvertTo-Base64 -Value 'Encode me, please!' -Encoding ([Text.Encoding]::ASCII)
Shows how to specify a custom encoding in case your string isn't in Unicode text encoding.
.EXAMPLE
'Encode me!' | ConvertTo-Base64
Converts `Encode me!` into a base-64 string.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[AllowNull()]
[AllowEmptyString()]
[string[]]
# The value to base-64 encoding.
$Value,
[Text.Encoding]
# The encoding to use. Default is Unicode.
$Encoding = ([Text.Encoding]::Unicode)
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
}
process
{
$Value | ForEach-Object {
if( $_ -eq $null )
{
return $null
}
$bytes = $Encoding.GetBytes($_)
[Convert]::ToBase64String($bytes)
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function ConvertTo-ContainerInheritanceFlags
{
<#
.SYNOPSIS
Converts a combination of InheritanceFlags Propagation Flags into a Carbon.Security.ContainerInheritanceFlags enumeration value.
.DESCRIPTION
`Grant-Permission`, `Test-Permission`, and `Get-Permission` all take an `ApplyTo` parameter, which is a `Carbon.Security.ContainerInheritanceFlags` enumeration value. This enumeration is then converted to the appropriate `System.Security.AccessControl.InheritanceFlags` and `System.Security.AccessControl.PropagationFlags` values for getting/granting/testing permissions. If you prefer to speak in terms of `InheritanceFlags` and `PropagationFlags`, use this function to convert them to a `ContainerInheritanceFlags` value.
If your combination doesn't result in a valid combination, `$null` is returned.
For detailed description of inheritance and propagation flags, see the help for `Grant-Permission`.
.OUTPUTS
Carbon.Security.ContainerInheritanceFlags.
.LINK
Grant-Permission
.LINK
Test-Permission
.EXAMPLE
ConvertTo-ContainerInheritanceFlags -InheritanceFlags 'ContainerInherit' -PropagationFlags 'None'
Demonstrates how to convert `InheritanceFlags` and `PropagationFlags` enumeration values into a `ContainerInheritanceFlags`. In this case, `[Carbon.Security.ContainerInheritanceFlags]::ContainerAndSubContainers` is returned.
#>
[CmdletBinding()]
[OutputType([Carbon.Security.ContainerInheritanceFlags])]
param(
[Parameter(Mandatory=$true,Position=0)]
[Security.AccessControl.InheritanceFlags]
# The inheritance flags to convert.
$InheritanceFlags,
[Parameter(Mandatory=$true,Position=1)]
[Security.AccessControl.PropagationFlags]
# The propagation flags to convert.
$PropagationFlags
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$propFlagsNone = $PropagationFlags -eq [Security.AccessControl.PropagationFlags]::None
$propFlagsInheritOnly = $PropagationFlags -eq [Security.AccessControl.PropagationFlags]::InheritOnly
$propFlagsInheritOnlyNoPropagate = $PropagationFlags -eq ([Security.AccessControl.PropagationFlags]::InheritOnly -bor [Security.AccessControl.PropagationFlags]::NoPropagateInherit)
$propFlagsNoPropagate = $PropagationFlags -eq [Security.AccessControl.PropagationFlags]::NoPropagateInherit
if( $InheritanceFlags -eq [Security.AccessControl.InheritanceFlags]::None )
{
return [Carbon.Security.ContainerInheritanceFlags]::Container
}
elseif( $InheritanceFlags -eq [Security.AccessControl.InheritanceFlags]::ContainerInherit )
{
if( $propFlagsInheritOnly )
{
return [Carbon.Security.ContainerInheritanceFlags]::SubContainers
}
elseif( $propFlagsInheritOnlyNoPropagate )
{
return [Carbon.Security.ContainerInheritanceFlags]::ChildContainers
}
elseif( $propFlagsNone )
{
return [Carbon.Security.ContainerInheritanceFlags]::ContainerAndSubContainers
}
elseif( $propFlagsNoPropagate )
{
return [Carbon.Security.ContainerInheritanceFlags]::ContainerAndChildContainers
}
}
elseif( $InheritanceFlags -eq [Security.AccessControl.InheritanceFlags]::ObjectInherit )
{
if( $propFlagsInheritOnly )
{
return [Carbon.Security.ContainerInheritanceFlags]::Leaves
}
elseif( $propFlagsInheritOnlyNoPropagate )
{
return [Carbon.Security.ContainerInheritanceFlags]::ChildLeaves
}
elseif( $propFlagsNone )
{
return [Carbon.Security.ContainerInheritanceFlags]::ContainerAndLeaves
}
elseif( $propFlagsNoPropagate )
{
return [Carbon.Security.ContainerInheritanceFlags]::ContainerAndChildLeaves
}
}
elseif( $InheritanceFlags -eq ([Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [Security.AccessControl.InheritanceFlags]::ObjectInherit ) )
{
if( $propFlagsInheritOnly )
{
return [Carbon.Security.ContainerInheritanceFlags]::SubContainersAndLeaves
}
elseif( $propFlagsInheritOnlyNoPropagate )
{
return [Carbon.Security.ContainerInheritanceFlags]::ChildContainersAndChildLeaves
}
elseif( $propFlagsNone )
{
return [Carbon.Security.ContainerInheritanceFlags]::ContainerAndSubContainersAndLeaves
}
elseif( $propFlagsNoPropagate )
{
return [Carbon.Security.ContainerInheritanceFlags]::ContainerAndChildContainersAndChildLeaves
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function ConvertTo-InheritanceFlag
{
<#
.SYNOPSIS
Converts a `Carbon.Security.ContainerInheritanceFlags` value to a `System.Security.AccessControl.InheritanceFlags` value.
.DESCRIPTION
The `Carbon.Security.ContainerInheritanceFlags` enumeration encapsulates oth `System.Security.AccessControl.InheritanceFlags` and `System.Security.AccessControl.PropagationFlags`. Make sure you also call `ConvertTo-PropagationFlag` to get the propagation value.
.OUTPUTS
System.Security.AccessControl.InheritanceFlags.
.LINK
ConvertTo-PropagationFlag
.LINK
Grant-Permission
.EXAMPLE
ConvertTo-InheritanceFlag -ContainerInheritanceFlag ContainerAndSubContainersAndLeaves
Returns `InheritanceFlags.ContainerInherit|InheritanceFlags.ObjectInherit`.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Carbon.Security.ContainerInheritanceFlags]
# The value to convert to an `InheritanceFlags` value.
[Alias('ContainerInheritanceFlags')]
$ContainerInheritanceFlag
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$Flags = [Security.AccessControl.InheritanceFlags]
$map = @{
'Container' = $Flags::None;
'SubContainers' = $Flags::ContainerInherit;
'Leaves' = $Flags::ObjectInherit;
'ChildContainers' = $Flags::ContainerInherit;
'ChildLeaves' = $Flags::ObjectInherit;
'ContainerAndSubContainers' = $Flags::ContainerInherit;
'ContainerAndLeaves' = $Flags::ObjectInherit;
'SubContainersAndLeaves' = ($Flags::ContainerInherit -bor $Flags::ObjectInherit);
'ContainerAndChildContainers' = $Flags::ContainerInherit;
'ContainerAndChildLeaves' = $Flags::ObjectInherit;
'ContainerAndChildContainersAndChildLeaves' = ($Flags::ContainerInherit -bor $Flags::ObjectInherit);
'ContainerAndSubContainersAndLeaves' = ($Flags::ContainerInherit -bor $Flags::ObjectInherit);
'ChildContainersAndChildLeaves' = ($Flags::ContainerInherit -bor $Flags::ObjectInherit);
}
$key = $ContainerInheritanceFlag.ToString()
if( $map.ContainsKey( $key) )
{
return $map[$key]
}
Write-Error ('Unknown Carbon.Security.ContainerInheritanceFlags enumeration value {0}.' -f $ContainerInheritanceFlag)
}
Set-Alias -Name 'ConvertTo-InheritanceFlags' -Value 'ConvertTo-InheritanceFlag'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function ConvertTo-PropagationFlag
{
<#
.SYNOPSIS
Converts a `Carbon.Security.ContainerInheritanceFlags` value to a `System.Security.AccessControl.PropagationFlags` value.
.DESCRIPTION
The `Carbon.Security.ContainerInheritanceFlags` enumeration encapsulates oth `System.Security.AccessControl.PropagationFlags` and `System.Security.AccessControl.InheritanceFlags`. Make sure you also call `ConvertTo-InheritancewFlags` to get the inheritance value.
.OUTPUTS
System.Security.AccessControl.PropagationFlags.
.LINK
ConvertTo-InheritanceFlag
.LINK
Grant-Permission
.EXAMPLE
ConvertTo-PropagationFlag -ContainerInheritanceFlag ContainerAndSubContainersAndLeaves
Returns `PropagationFlags.None`.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Carbon.Security.ContainerInheritanceFlags]
# The value to convert to an `PropagationFlags` value.
[Alias('ContainerInheritanceFlags')]
$ContainerInheritanceFlag
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$Flags = [Security.AccessControl.PropagationFlags]
$map = @{
'Container' = $Flags::None;
'SubContainers' = $Flags::InheritOnly;
'Leaves' = $Flags::InheritOnly;
'ChildContainers' = ($Flags::InheritOnly -bor $Flags::NoPropagateInherit);
'ChildLeaves' = ($Flags::InheritOnly -bor $Flags::NoPropagateInherit);
'ContainerAndSubContainers' = $Flags::None;
'ContainerAndLeaves' = $Flags::None;
'SubContainersAndLeaves' = $Flags::InheritOnly;
'ContainerAndChildContainers' = $Flags::NoPropagateInherit;
'ContainerAndChildLeaves' = $Flags::NoPropagateInherit;
'ContainerAndChildContainersAndChildLeaves' = $Flags::NoPropagateInherit;
'ContainerAndSubContainersAndLeaves' = $Flags::None;
'ChildContainersAndChildLeaves' = ($Flags::InheritOnly -bor $Flags::NoPropagateInherit);
}
$key = $ContainerInheritanceFlag.ToString()
if( $map.ContainsKey( $key ) )
{
return $map[$key]
}
Write-Error ('Unknown Carbon.Security.ContainerInheritanceFlags enumeration value {0}.' -f $ContainerInheritanceFlag)
}
Set-Alias -Name 'ConvertTo-PropagationFlags' -Value 'ConvertTo-PropagationFlag'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function ConvertTo-ProviderAccessControlRights
{
<#
.SYNOPSIS
Converts strings into the appropriate access control rights for a PowerShell provider (e.g. FileSystemRights or RegistryRights).
.DESCRIPTION
This is an internal Carbon function, so you're not getting anything more than the synopsis.
.EXAMPLE
ConvertTo-ProviderAccessControlRights -ProviderName 'FileSystem' -InputObject 'Read','Write'
Demonstrates how to convert `Read` and `Write` into a `System.Security.AccessControl.FileSystemRights` value.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[ValidateSet('FileSystem','Registry','CryptoKey')]
[string]
# The provider name.
$ProviderName,
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[string[]]
# The values to convert.
$InputObject
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$rights = 0
$rightTypeName = 'Security.AccessControl.{0}Rights' -f $ProviderName
$foundInvalidRight = $false
}
process
{
$InputObject | ForEach-Object {
$right = ($_ -as $rightTypeName)
if( -not $right )
{
$allowedValues = [Enum]::GetNames($rightTypeName)
Write-Error ("System.Security.AccessControl.{0}Rights value '{1}' not found. Must be one of: {2}." -f $providerName,$_,($allowedValues -join ' '))
$foundInvalidRight = $true
return
}
$rights = $rights -bor $right
}
}
end
{
if( $foundInvalidRight )
{
return $null
}
else
{
$rights
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function ConvertTo-SecurityIdentifier
{
<#
.SYNOPSIS
Converts a string or byte array security identifier into a `System.Security.Principal.SecurityIdentifier` object.
.DESCRIPTION
`ConvertTo-SecurityIdentifier` converts a SID in SDDL form (as a string), in binary form (as a byte array) into a `System.Security.Principal.SecurityIdentifier` object. It also accepts `System.Security.Principal.SecurityIdentifier` objects, and returns them back to you.
If the string or byte array don't represent a SID, an error is written and nothing is returned.
.LINK
Resolve-Identity
.LINK
Resolve-IdentityName
.EXAMPLE
Resolve-Identity -SID 'S-1-5-21-2678556459-1010642102-471947008-1017'
Demonstrates how to convert a a SID in SDDL into a `System.Security.Principal.SecurityIdentifier` object.
.EXAMPLE
Resolve-Identity -SID (New-Object 'Security.Principal.SecurityIdentifier' 'S-1-5-21-2678556459-1010642102-471947008-1017')
Demonstrates that you can pass a `SecurityIdentifier` object as the value of the SID parameter. The SID you passed in will be returned to you unchanged.
.EXAMPLE
Resolve-Identity -SID $sidBytes
Demonstrates that you can use a byte array that represents a SID as the value of the `SID` parameter.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
# The SID to convert to a `System.Security.Principal.SecurityIdentifier`. Accepts a SID in SDDL form as a `string`, a `System.Security.Principal.SecurityIdentifier` object, or a SID in binary form as an array of bytes.
$SID
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
try
{
if( $SID -is [string] )
{
New-Object 'Security.Principal.SecurityIdentifier' $SID
}
elseif( $SID -is [byte[]] )
{
New-Object 'Security.Principal.SecurityIdentifier' $SID,0
}
elseif( $SID -is [Security.Principal.SecurityIdentifier] )
{
$SID
}
else
{
Write-Error ('Invalid SID. The `SID` parameter accepts a `System.Security.Principal.SecurityIdentifier` object, a SID in SDDL form as a `string`, or a SID in binary form as byte array. You passed a ''{0}''.' -f $SID.GetType())
return
}
}
catch
{
Write-Error ('Exception converting SID parameter to a `SecurityIdentifier` object. This usually means you passed an invalid SID in SDDL form (as a string) or an invalid SID in binary form (as a byte array): {0}' -f $_.Exception.Message)
return
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Copy-DscResource
{
<#
.SYNOPSIS
Copies DSC resources.
.DESCRIPTION
This function copies a DSC resource or a directory of DSC resources to a DSC pull server share/website. All files under `$Path` are copied.
DSC requires all files have a checksum file (e.g. `localhost.mof.checksum`), which this function generates for you (in a temporary location).
Only new files, or files whose checksums have changed, are copied. You can force all files to be copied with the `Force` switch.
`Copy-DscResource` is new in Carbon 2.0.
.EXAMPLE
Copy-DscResource -Path 'localhost.mof' -Destination '\\dscserver\DscResources'
Demonstrates how to copy a single resource to a resources SMB share. `localhost.mof` will only be copied if its checksum is different than what is in `\\dscserver\DscResources`.
.EXAMPLE
Copy-DscResource -Path 'C:\Projects\DscResources' -Destination '\\dscserver\DscResources'
Demonstrates how to copy a directory of resources. Only files in the directory are copied. Every file in the source must have a `.checksum` file. Only files whose checksums are different between source and destination will be copied.
.EXAMPLE
Copy-DscResource -Path 'C:\Projects\DscResources' -Destination '\\dscserver\DscResources' -Recurse
Demonstrates how to recursively copy files.
.EXAMPLE
Copy-DscResource -Path 'C:\Projects\DscResources' -Destination '\\dscserver\DscResources' -Force
Demonstrates how to copy all files, even if their `.checksum` files are the same.
.EXAMPLE
Copy-DscResource -Path 'C:\Projects\DscResources' -Destination '\\dscserver\DscResources' -PassThru
Demonstrates how to get `System.IO.FileInfo` objects for all resources copied to the destination. If all files are up-to-date, nothing is copied, and no objects are returned.
#>
[CmdletBinding()]
[OutputType([IO.FileInfo])]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to the DSC resource to copy. If a directory is given, all files in that directory are copied. Wildcards supported.
$Path,
[Parameter(Mandatory=$true)]
[string]
# The directory where the resources should be copied.
$Destination,
[Switch]
# Recursively copy files from the source directory.
$Recurse,
[Switch]
# Returns `IO.FileInfo` objects for each item copied to `Destination`.
$PassThru,
[Switch]
# Copy resources, even if they are the same on the destination server.
$Force
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$tempDir = New-TempDirectory -Prefix 'Carbon+Copy-DscResource+'
try
{
foreach( $item in (Get-ChildItem -Path $Path -Exclude '*.checksum') )
{
$destinationPath = Join-Path -Path $Destination -ChildPath $item.Name
if( $item.PSIsContainer )
{
if( $Recurse )
{
if( -not (Test-Path -Path $destinationPath -PathType Container) )
{
New-Item -Path $destinationPath -ItemType 'Directory' | Out-Null
}
Copy-DscResource -Path $item.FullName -Destination $destinationPath -Recurse -Force:$Force -PassThru:$PassThru
}
continue
}
$sourceChecksumPath = '{0}.checksum' -f $item.Name
$sourceChecksumPath = Join-Path -Path $tempDir -ChildPath $sourceChecksumPath
$sourceChecksum = Get-FileHash -Path $item.FullName | Select-Object -ExpandProperty 'Hash'
# hash files can't have any newline characters, so we can't use Set-Content
[IO.File]::WriteAllText($sourceChecksumPath, $sourceChecksum)
$destinationChecksum = ''
$destinationChecksumPath = '{0}.checksum' -f $destinationPath
if( (Test-Path -Path $destinationChecksumPath -PathType Leaf) )
{
$destinationChecksum = Get-Content -TotalCount 1 -Path $destinationChecksumPath
}
if( $Force -or -not (Test-Path -Path $destinationPath -PathType Leaf) -or ($sourceChecksum -ne $destinationChecksum) )
{
Copy-Item -Path $item -Destination $Destination -PassThru:$PassThru
Copy-Item -Path $sourceChecksumPath -Destination $Destination -PassThru:$PassThru
}
else
{
Write-Verbose ('File ''{0}'' already up-to-date.' -f $destinationPath)
}
}
}
finally
{
Remove-Item -Path $tempDir -Recurse -Force -ErrorAction Ignore
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Disable-FirewallStatefulFtp
{
<#
.SYNOPSIS
Disables the `StatefulFtp` Windows firewall setting.
.DESCRIPTION
Uses the `netsh` command to disable the `StatefulFtp` Windows firewall setting.
If the firewall isn't configurable, writes an error and returns without making any changes.
.LINK
Assert-FirewallConfigurable
.EXAMPLE
Disable-FirewallStatefulFtp
Disables the `StatefulFtp` Windows firewall setting.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Assert-FirewallConfigurable) )
{
return
}
Invoke-ConsoleCommand -Target 'firewall' `
-Action 'disabling stateful FTP' `
-ScriptBlock {
netsh advfirewall set global StatefulFtp disable
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Disable-IEEnhancedSecurityConfiguration
{
<#
.SYNOPSIS
Disables Internet Explorer's Enhanced Security Configuration.
.DESCRIPTION
By default, Windows locks down Internet Explorer so that users can't visit certain sites. This function disables that enhanced security. This is necessary if you have automated processes that need to run and interact with Internet Explorer.
You may also need to call `Enable-IEActivationPermission`, so that processes have permission to start Internet Explorer.
.EXAMPLE
Disable-IEEnhancedSecurityConfiguration
.LINK
http://technet.microsoft.com/en-us/library/dd883248(v=WS.10).aspx
.LINK
Enable-IEActivationPermission
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$adminPath = "SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}"
$userPath = "SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}"
# Yes. They are different. Right here ^
$paths = @( $adminPath, $userPath )
if( $PSCmdlet.ShouldProcess( 'Internet Explorer', 'disabling enhanced security configuration' ) )
{
foreach( $path in $paths )
{
$hklmPath = Join-Path -Path 'hklm:\' -ChildPath $path
if( -not (Test-Path -Path $hklmPath) )
{
Write-Warning ('Applying Enhanced Security Configuration registry key ''{0}'' not found.' -f $hklmPath)
return
}
Set-RegistryKeyValue -Path $hklmPath -Name 'IsInstalled' -DWord 0
}
Write-Verbose ('Calling iesetup.dll hardening methods.')
Rundll32 iesetup.dll, IEHardenLMSettings
Rundll32 iesetup.dll, IEHardenUser
Rundll32 iesetup.dll, IEHardenAdmin
foreach( $path in $paths )
{
$hkcuPath = Join-Path -Path 'hkcu:\' -ChildPath $path
if( Test-Path -Path $hkcuPath )
{
Remove-Item -Path $hkcuPath
}
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Disable-IisSecurityAuthentication
{
<#
.SYNOPSIS
Disables anonymous or basic authentication for all or part of a website.
.DESCRIPTION
By default, disables an authentication type for an entire website. You can disable an authentication type at a specific path under a website by passing the virtual path (*not* the physical path) to that directory as the value of the `VirtualPath` parameter.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
Enable-IisSecurityAuthentication
.LINK
Get-IisSecurityAuthentication
.LINK
Test-IisSecurityAuthentication
.EXAMPLE
Disable-IisSecurityAuthentication -SiteName Peanuts -Anonymous
Turns off anonymous authentication for the `Peanuts` website.
.EXAMPLE
Disable-IisSecurityAuthentication -SiteName Peanuts Snoopy/DogHouse -Basic
Turns off basic authentication for the `Snoopy/DogHouse` directory under the `Peanuts` website.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The site where anonymous authentication should be set.
$SiteName,
[Alias('Path')]
[string]
# The optional path where anonymous authentication should be set.
$VirtualPath = '',
[Parameter(Mandatory=$true,ParameterSetName='Anonymous')]
[Switch]
# Enable anonymouse authentication.
$Anonymous,
[Parameter(Mandatory=$true,ParameterSetName='Basic')]
[Switch]
# Enable basic authentication.
$Basic,
[Parameter(Mandatory=$true,ParameterSetName='Windows')]
[Switch]
# Enable Windows authentication.
$Windows
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$authType = $pscmdlet.ParameterSetName
$getArgs = @{ $authType = $true; }
$authSettings = Get-IisSecurityAuthentication -SiteName $SiteName -VirtualPath $VirtualPath @getArgs
$authSettings.SetAttributeValue('enabled', 'False')
$fullPath = Join-IisVirtualPath $SiteName $VirtualPath
if( $pscmdlet.ShouldProcess( $fullPath, ("disable {0} authentication" -f $authType) ) )
{
$authSettings.CommitChanges()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Disable-NtfsCompression
{
<#
.SYNOPSIS
Turns off NTFS compression on a file/directory.
.DESCRIPTION
When disabling compression for a directory, any compressed files/directories in that directory will remain compressed. To decompress everything, use the `-Recurse` switch. This could take awhile.
Uses Windows' `compact.exe` command line utility to compress the file/directory. To see the output from `compact.exe`, set the `Verbose` switch.
.LINK
Enable-NtfsCompression
.LINK
Test-NtfsCompression
.EXAMPLE
Disable-NtfsCompression -Path C:\Projects\Carbon
Turns off NTFS compression on and decompresses the `C:\Projects\Carbon` directory, but not its sub-directories/files. New files/directories will get compressed.
.EXAMPLE
Disable-NtfsCompression -Path C:\Projects\Carbon -Recurse
Turns off NTFS compression on and decompresses the `C:\Projects\Carbon` directory and all its sub-directories/sub-files.
.EXAMPLE
Get-ChildItem * | Where-Object { $_.PsIsContainer } | Disable-NtfsCompression
Demonstrates that you can pipe the path to compress into `Disable-NtfsCompression`.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string[]]
[Alias('FullName')]
# The path where compression should be disabled.
$Path,
[Switch]
# Disables compression on all sub-directories.
$Recurse
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$compactPath = Join-Path $env:SystemRoot 'system32\compact.exe'
if( -not (Test-Path -Path $compactPath -PathType Leaf) )
{
if( (Get-Command -Name 'compact.exe' -ErrorAction SilentlyContinue) )
{
$compactPath = 'compact.exe'
}
else
{
Write-Error ("Compact command '{0}' not found." -f $compactPath)
return
}
}
}
process
{
foreach( $item in $Path )
{
if( -not (Test-Path -Path $item) )
{
Write-Error -Message ('Path {0} not found.' -f $item) -Category ObjectNotFound
return
}
$recurseArg = ''
$pathArg = $item
if( (Test-Path -Path $item -PathType Container) )
{
if( $Recurse )
{
$recurseArg = ('/S:{0}' -f $item)
$pathArg = ''
}
}
Invoke-ConsoleCommand -Target $item -Action 'disable NTFS compression' -ScriptBlock {
& $compactPath /U $recurseArg $pathArg
}
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Enable-FirewallStatefulFtp
{
<#
.SYNOPSIS
Enables the `StatefulFtp` Windows firewall setting.
.DESCRIPTION
Uses the `netsh` command to enable the `StatefulFtp` Windows firewall setting.
If the firewall isn't configurable, writes an error and returns without making any changes.
.LINK
Assert-FirewallConfigurable
.EXAMPLE
Enable-FirewallStatefulFtp
Enables the `StatefulFtp` Windows firewall setting.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Assert-FirewallConfigurable) )
{
return
}
Invoke-ConsoleCommand -Target 'firewall' -Action 'enable stateful FTP' -ScriptBlock {
netsh advfirewall set global StatefulFtp enable
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Enable-IisDirectoryBrowsing
{
<#
.SYNOPSIS
Enables directory browsing under all or part of a website.
.DESCRIPTION
Enables directory browsing (i.e. showing the contents of a directory by requesting that directory in a web browser) for a website. To enable directory browsing on a directory under the website, pass the virtual path to that directory as the value to the `Directory` parameter.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Enable-IisDirectoryBrowsing -SiteName Peanuts
Enables directory browsing on the `Peanuts` website.
.EXAMPLE
Enable-IisDirectoryBrowsing -SiteName Peanuts -Directory Snoopy/DogHouse
Enables directory browsing on the `/Snoopy/DogHouse` directory under the `Peanuts` website.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the site where the virtual directory is located.
$SiteName,
[Alias('Path')]
[string]
# The directory where directory browsing should be enabled.
$VirtualPath
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$section = Get-IisConfigurationSection -SiteName $SiteName -SectionPath 'system.webServer/directoryBrowse'
if( $section['enabled'] -ne 'true' )
{
Write-IisVerbose $SiteName 'Directory Browsing' 'disabled' 'enabled'
$section['enabled'] = $true
$section.CommitChanges()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Enable-IisSecurityAuthentication
{
<#
.SYNOPSIS
Enables anonymous or basic authentication for an entire site or a sub-directory of that site.
.DESCRIPTION
By default, enables an authentication type on an entire website. You can enable an authentication type at a specific path under a website by passing the virtual path (*not* the physical path) to that directory as the value of the `VirtualPath` parameter.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
Disable-IisSecurityAuthentication
.LINK
Get-IisSecurityAuthentication
.LINK
Test-IisSecurityAuthentication
.EXAMPLE
Enable-IisSecurityAuthentication -SiteName Peanuts -Anonymous
Turns on anonymous authentication for the `Peanuts` website.
.EXAMPLE
Enable-IisSecurityAuthentication -SiteName Peanuts Snoopy/DogHouse -Basic
Turns on anonymous authentication for the `Snoopy/DogHouse` directory under the `Peanuts` website.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The site where anonymous authentication should be set.
$SiteName,
[Alias('Path')]
[string]
# The optional path where anonymous authentication should be set.
$VirtualPath = '',
[Parameter(Mandatory=$true,ParameterSetName='Anonymous')]
[Switch]
# Enable anonymouse authentication.
$Anonymous,
[Parameter(Mandatory=$true,ParameterSetName='Basic')]
[Switch]
# Enable basic authentication.
$Basic,
[Parameter(Mandatory=$true,ParameterSetName='Windows')]
[Switch]
# Enable Windows authentication.
$Windows
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$authType = $pscmdlet.ParameterSetName
$getArgs = @{ $authType = $true; }
$authSettings = Get-IisSecurityAuthentication -SiteName $SiteName -VirtualPath $VirtualPath @getArgs
$authSettings.SetAttributeValue('enabled', 'true')
$fullPath = Join-IisVirtualPath $SiteName $VirtualPath
if( $pscmdlet.ShouldProcess( $fullPath, ("enable {0}" -f $authType) ) )
{
$authSettings.CommitChanges()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Enable-IisSsl
{
<#
.SYNOPSIS
Turns on and configures SSL for a website or part of a website.
.DESCRIPTION
This function enables SSL and optionally the site/directory to:
* Require SSL (the `RequireSsl` switch)
* Ignore/accept/require client certificates (the `AcceptClientCertificates` and `RequireClientCertificates` switches).
* Requiring 128-bit SSL (the `Require128BitSsl` switch).
By default, this function will enable SSL, make SSL connections optional, ignores client certificates, and not require 128-bit SSL.
Changing any SSL settings will do you no good if the website doesn't have an SSL binding or doesn't have an SSL certificate. The configuration will most likely succeed, but won't work in a browser. So sad.
Beginning with IIS 7.5, the `Require128BitSsl` parameter won't actually change the behavior of a website since [there are no longer 128-bit crypto providers](https://forums.iis.net/p/1163908/1947203.aspx) in versions of Windows running IIS 7.5.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
http://support.microsoft.com/?id=907274
.EXAMPLE
Enable-IisSsl -Site Peanuts
Enables SSL on the `Peanuts` website's, making makes SSL connections optional, ignoring client certificates, and making 128-bit SSL optional.
.EXAMPLE
Enable-IisSsl -Site Peanuts -VirtualPath Snoopy/DogHouse -RequireSsl
Configures the `/Snoopy/DogHouse` directory in the `Peanuts` site to require SSL. It also turns off any client certificate settings and makes 128-bit SSL optional.
.EXAMPLE
Enable-IisSsl -Site Peanuts -AcceptClientCertificates
Enables SSL on the `Peanuts` website and configures it to accept client certificates, makes SSL optional, and makes 128-bit SSL optional.
.EXAMPLE
Enable-IisSsl -Site Peanuts -RequireSsl -RequireClientCertificates
Enables SSL on the `Peanuts` website and configures it to require SSL and client certificates. You can't require client certificates without also requiring SSL.
.EXAMPLE
Enable-IisSsl -Site Peanuts -Require128BitSsl
Enables SSL on the `Peanuts` website and require 128-bit SSL. Also, makes SSL connections optional and ignores client certificates.
.LINK
Set-IisWebsiteSslCertificate
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='IgnoreClientCertificates')]
param(
[Parameter(Mandatory=$true)]
[string]
# The website whose SSL flags should be modifed.
$SiteName,
[Alias('Path')]
[string]
# The path to the folder/virtual directory/application under the website whose SSL flags should be set.
$VirtualPath = '',
[Parameter(ParameterSetName='IgnoreClientCertificates')]
[Parameter(ParameterSetName='AcceptClientCertificates')]
[Parameter(Mandatory=$true,ParameterSetName='RequireClientCertificates')]
[Switch]
# Should SSL be required?
$RequireSsl,
[Switch]
# Requires 128-bit SSL. Only changes IIS behavior in IIS 7.0.
$Require128BitSsl,
[Parameter(ParameterSetName='AcceptClientCertificates')]
[Switch]
# Should client certificates be accepted?
$AcceptClientCertificates,
[Parameter(Mandatory=$true,ParameterSetName='RequireClientCertificates')]
[Switch]
# Should client certificates be required? Also requires SSL ('RequireSsl` switch).
$RequireClientCertificates
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$SslFlags_Ssl = 8
$SslFlags_SslNegotiateCert = 32
$SslFlags_SslRequireCert = 64
$SslFlags_SslMapCert = 128
$SslFlags_Ssl128 = 256
$intFlag = 0
$flags = @()
if( $RequireSSL -or $RequireClientCertificates )
{
$flags += 'Ssl'
$intFlag = $intFlag -bor $SslFlags_Ssl
}
if( $AcceptClientCertificates -or $RequireClientCertificates )
{
$flags += 'SslNegotiateCert'
$intFlag = $intFlag -bor $SslFlags_SslNegotiateCert
}
if( $RequireClientCertificates )
{
$flags += 'SslRequireCert'
$intFlag = $intFlag -bor $SslFlags_SslRequireCert
}
if( $Require128BitSsl )
{
$flags += 'Ssl128'
$intFlag = $intFlag -bor $SslFlags_Ssl128
}
$section = Get-IisConfigurationSection -SiteName $SiteName -VirtualPath $VirtualPath -SectionPath 'system.webServer/security/access'
if( -not $section )
{
return
}
$flags = $flags -join ','
$currentIntFlag = $section['sslFlags']
$currentFlags = @( )
if( $currentIntFlag -band $SslFlags_Ssl )
{
$currentFlags += 'Ssl'
}
if( $currentIntFlag -band $SslFlags_SslNegotiateCert )
{
$currentFlags += 'SslNegotiateCert'
}
if( $currentIntFlag -band $SslFlags_SslRequireCert )
{
$currentFlags += 'SslRequireCert'
}
if( $currentIntFlag -band $SslFlags_SslMapCert )
{
$currentFlags += 'SslMapCert'
}
if( $currentIntFlag -band $SslFlags_Ssl128 )
{
$currentFlags += 'Ssl128'
}
if( -not $currentFlags )
{
$currentFlags += 'None'
}
$currentFlags = $currentFlags -join ','
if( $section['sslFlags'] -ne $intFlag )
{
Write-IisVerbose $SiteName 'SslFlags' ('{0} ({1})' -f $currentIntFlag,$currentFlags) ('{0} ({1})' -f $intFlag,$flags) -VirtualPath $VirtualPath
$section['sslFlags'] = $flags
if( $pscmdlet.ShouldProcess( (Join-IisVirtualPath $SiteName $VirtualPath), "enable SSL" ) )
{
$section.CommitChanges()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Enable-NtfsCompression
{
<#
.SYNOPSIS
Turns on NTFS compression on a file/directory.
.DESCRIPTION
By default, when enabling compression on a directory, only new files/directories created *after* enabling compression will be compressed. To compress everything, use the `-Recurse` switch.
Uses Windows' `compact.exe` command line utility to compress the file/directory. To see the output from `compact.exe`, set the `Verbose` switch.
.LINK
Disable-NtfsCompression
.LINK
Test-NtfsCompression
.EXAMPLE
Enable-NtfsCompression -Path C:\Projects\Carbon
Turns on NTFS compression on and compresses the `C:\Projects\Carbon` directory, but not its sub-directories.
.EXAMPLE
Enable-NtfsCompression -Path C:\Projects\Carbon -Recurse
Turns on NTFS compression on and compresses the `C:\Projects\Carbon` directory and all its sub-directories.
.EXAMPLE
Get-ChildItem * | Where-Object { $_.PsIsContainer } | Enable-NtfsCompression
Demonstrates that you can pipe the path to compress into `Enable-NtfsCompression`.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string[]]
[Alias('FullName')]
# The path where compression should be enabled.
$Path,
[Switch]
# Enables compression on all sub-directories.
$Recurse
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$compactPath = Join-Path $env:SystemRoot 'system32\compact.exe'
if( -not (Test-Path -Path $compactPath -PathType Leaf) )
{
if( (Get-Command -Name 'compact.exe' -ErrorAction SilentlyContinue) )
{
$compactPath = 'compact.exe'
}
else
{
Write-Error ("Compact command '{0}' not found." -f $compactPath)
return
}
}
}
process
{
foreach( $item in $Path )
{
if( -not (Test-Path -Path $item) )
{
Write-Error -Message ('Path {0} not found.' -f $item) -Category ObjectNotFound
return
}
$recurseArg = ''
$pathArg = $item
if( (Test-Path -Path $item -PathType Container) )
{
if( $Recurse )
{
$recurseArg = ('/S:{0}' -f $item)
$pathArg = ''
}
}
Invoke-ConsoleCommand -Target $item -Action 'enable NTFS compression' -ScriptBlock {
& $compactPath /C $recurseArg $pathArg
}
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Find-ADUser
{
<#
.SYNOPSIS
Finds a user in Active Directory.
.DESCRIPTION
Searches the Active Directory domain given by `DomainUrl` for a user whose `sAMAccountName` matches the `sAMAccountName` passed in. Returns the `DirectoryEntry` object for that user. If there are any errors communicating with the domain controller, `$null` is returned.
.OUTPUTS
System.DirectoryServices.DirectoryEntry. The directory entry object of the user's account in Active Directory or `$null` if the user isn't found.
.LINK
http://msdn.microsoft.com/en-us/library/aa746475.aspx
.EXAMPLE
Find-ADUser -DomainUrl LDAP://dc.example.com:389 -sAMAccountName $env:USERNAME
Finds the AD user whose Windows username (sAMAccountName) is equal to thecurrently logged on user's username.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The LDAP URL to the domain controller to contact.
$DomainUrl,
[Parameter(Mandatory=$true,ParameterSetName='BysAMAccountName')]
[string]
# Search by a user's sAMAcountName (i.e. Windows username). Special
# characters are escaped.
$sAMAccountName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$domain = [adsi] $DomainUrl
$searcher = [adsisearcher] $domain
$filterPropertyName = 'sAMAccountName'
$filterPropertyValue = $sAMAccountName
$filterPropertyValue = Format-ADSearchFilterValue $filterPropertyValue
$searcher.Filter = "(&(objectClass=User) ($filterPropertyName=$filterPropertyValue))"
try
{
$result = $searcher.FindOne()
if( $result )
{
$result.GetDirectoryEntry()
}
}
catch
{
Write-Error ("Exception finding user {0} on domain controller {1}: {2}" -f $sAMAccountName,$DomainUrl,$_.Exception.Message)
return $null
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Format-ADSearchFilterValue
{
<#
.SYNOPSIS
Escapes Active Directory special characters from a string.
.DESCRIPTION
There are special characters in Active Directory queries/searches. This function escapes them so they aren't treated as AD commands/characters.
.OUTPUTS
System.String. The input string with any Active Directory-sensitive characters escaped.
.LINK
http://msdn.microsoft.com/en-us/library/aa746475.aspx#special_characters
.EXAMPLE
Format-ADSearchFilterValue -String "I have AD special characters (I think)."
Returns
I have AD special characters \28I think\29.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The string to escape.
$String
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$string = $string.Replace('\', '\5c')
$string = $string.Replace('*', '\2a')
$string = $string.Replace('(', '\28')
$string = $string.Replace(')', '\29')
$string = $string.Replace('/', '\2f')
$string.Replace("`0", '\00')
}
Set-Alias -Name 'Format-ADSpecialCharacters' -Value 'Format-ADSearchFilterValue'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-ADDomainController
{
<#
.SYNOPSIS
Gets the domain controller of the current computer's domain, or for a
specific domain.
.DESCRIPTION
When working with Active Directory, it's important to have the hostname of
the domain controller you need to work with. This function will find the
domain controller for the domain of the current computer or the domain
controller for a given domain.
.OUTPUTS
System.String. The hostname for the domain controller. If the domain
controller is not found, $null is returned.
.EXAMPLE
> Get-ADDomainController
Returns the domain controller for the current computer's domain.
Approximately equivialent to the hostname given in the LOGONSERVER
environment variable.
.EXAMPLE
> Get-ADDomainController -Domain MYDOMAIN
Returns the domain controller for the MYDOMAIN domain.
#>
[CmdletBinding()]
param(
[string]
# The domain whose domain controller to get. If not given, gets the
# current computer's domain controller.
$Domain
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $Domain )
{
$principalContext = $null
try
{
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$principalContext = New-Object DirectoryServices.AccountManagement.PrincipalContext Domain,$Domain
return $principalContext.ConnectedServer
}
catch
{
$firstException = $_.Exception
while( $firstException.InnerException )
{
$firstException = $firstException.InnerException
}
Write-Error ("Unable to find domain controller for domain '{0}': {1}: {2}" -f $Domain,$firstException.GetType().FullName,$firstException.Message)
return $null
}
finally
{
if( $principalContext )
{
$principalContext.Dispose()
}
}
}
else
{
$root = New-Object DirectoryServices.DirectoryEntry "LDAP://RootDSE"
try
{
return $root.Properties["dnsHostName"][0].ToString();
}
finally
{
$root.Dispose()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-Certificate
{
<#
.SYNOPSIS
Gets a certificate from a file on the file system or from a Windows certificate store by thumbprint or friendly name.
.DESCRIPTION
Certificates can be files or they can be in a Windows certificate store. This function returns an `X509Certificate2` object for a script that's a file on the file system or a cert stored in Microsoft's certificate store. You can get a certificate from a certificate store with its unique thumbprint or its friendly name. Friendly names are *not* required to be unique, so you may get multiple certificates when using that search method.
Certificates loaded from a file are imported with default key storage values, which means if you try to add the certifiate returned by this function to a certificate store it will get persisted in the user's key store and *not* persisted.
.OUTPUTS
System.Security.Cryptography.x509Certificates.X509Certificate2. The X509Certificate2 certificates that were found, or `$null`.
.EXAMPLE
Get-Certificate -Path C:\Certificates\certificate.cer -Password MySuperSecurePassword
Gets an X509Certificate2 object representing the certificate.cer file. Wildcards *not* supported when using a file system path.
.EXAMPLE
Get-Certificate -Thumbprint a909502dd82ae41433e6f83886b00d4277a32a7b -StoreName My -StoreLocation LocalMachine
Gets an X509Certificate2 object for the certificate in the Personal store with a specific thumbprint under the Local Machine.
.EXAMPLE
Get-Certificate -FriendlyName 'Development Certificate' -StoreLocation CurrentUser -StoreName TrustedPeople
Gets the X509Certificate2 whose friendly name is Development Certificate from the Current User's Trusted People certificate store.
.EXAMPLE
Get-Certificate -Thumbprint a909502dd82ae41433e6f83886b00d4277a32a7b -CustomStoreName 'SharePoint' -StoreLocation LocalMachine
Demonstrates how to get a certificate from a custom store, i.e. one that is not part of the standard `StoreName` enumeration.
.EXAMPLE
Get-Certificate -Path 'cert:\CurrentUser\a909502dd82ae41433e6f83886b00d4277a32a7b'
Demonstrates how to get a certificate out of a Windows certificate store with its certificate path. Wildcards supported.
#>
[CmdletBinding(DefaultParameterSetName='ByFriendlyName')]
[OutputType([Security.Cryptography.X509Certificates.X509Certificate2])]
param(
[Parameter(Mandatory=$true,ParameterSetName='ByPath')]
[string]
# The path to the certificate. Can be a file system path or a certificate path, e.g. `cert:\`. Wildcards supported.
$Path,
[Parameter(ParameterSetName='ByPath')]
# The password to the certificate. Can be plaintext or a [SecureString](http://msdn.microsoft.com/en-us/library/system.securestring.aspx).
$Password,
[Parameter(ParameterSetName='ByPath')]
[Security.Cryptography.X509Certificates.X509KeyStorageFlags]
# The storage flags to use when loading a certificate file. This controls where/how you can store the certificate in the certificate stores later. Use the `-bor` operator to combine flags.
$KeyStorageFlags,
[Parameter(Mandatory=$true,ParameterSetName='ByThumbprint')]
[Parameter(Mandatory=$true,ParameterSetName='ByThumbprintCustomStoreName')]
[string]
# The certificate's thumbprint.
$Thumbprint,
[Parameter(Mandatory=$true,ParameterSetName='ByFriendlyName')]
[Parameter(Mandatory=$true,ParameterSetName='ByFriendlyNameCustomStoreName')]
[string]
# The friendly name of the certificate.
$FriendlyName,
[Parameter(Mandatory=$true,ParameterSetName='ByFriendlyName')]
[Parameter(Mandatory=$true,ParameterSetName='ByFriendlyNameCustomStoreName')]
[Parameter(Mandatory=$true,ParameterSetName='ByThumbprint')]
[Parameter(Mandatory=$true,ParameterSetName='ByThumbprintCustomStoreName')]
[Security.Cryptography.X509Certificates.StoreLocation]
# The location of the certificate's store.
$StoreLocation,
[Parameter(Mandatory=$true,ParameterSetName='ByFriendlyName')]
[Parameter(Mandatory=$true,ParameterSetName='ByThumbprint')]
[Security.Cryptography.X509Certificates.StoreName]
# The name of the certificate's store.
$StoreName,
[Parameter(Mandatory=$true,ParameterSetName='ByFriendlyNameCustomStoreName')]
[Parameter(Mandatory=$true,ParameterSetName='ByThumbprintCustomStoreName')]
[string]
# The name of the non-standard, custom store.
$CustomStoreName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSCmdlet.ParameterSetName -eq 'ByPath' )
{
if( -not (Test-Path -Path $Path -PathType Leaf) )
{
Write-Error ('Certificate ''{0}'' not found.' -f $Path)
return
}
Get-Item -Path $Path |
ForEach-Object {
$item = $_
if( $item -is [Security.Cryptography.X509Certificates.X509Certificate2] )
{
return $item
}
elseif( $item -is [IO.FileInfo] )
{
try
{
$ctorParams = @( $item.FullName, $Password )
if( $KeyStorageFlags )
{
$ctorParams += $KeyStorageFlags
}
return New-Object 'Security.Cryptography.X509Certificates.X509Certificate2' $ctorParams
}
catch
{
$ex = $_.Exception
while( $ex.InnerException )
{
$ex = $ex.InnerException
}
Write-Error -Message ('Failed to create X509Certificate2 object from file ''{0}'': {1}' -f $item.FullName,$ex.Message)
}
}
}
}
else
{
$storeLocationPath = '*'
if( $StoreLocation )
{
$storeLocationPath = $StoreLocation
}
$storeNamePath = '*'
if( $PSCmdlet.ParameterSetName -like '*CustomStoreName' )
{
$storeNamePath = $CustomStoreName
}
else
{
$storeNamePath = $StoreName
if( $StoreName -eq [Security.Cryptography.X509Certificates.StoreName]::CertificateAuthority )
{
$storeNamePath = 'CA'
}
}
if( $pscmdlet.ParameterSetName -like 'ByThumbprint*' )
{
$certPath = 'cert:\{0}\{1}\{2}' -f $storeLocationPath,$storeNamePath,$Thumbprint
if( (Test-Path -Path $certPath) )
{
return Get-ChildItem -Path $certPath
}
return
}
elseif( $PSCmdlet.ParameterSetName -like 'ByFriendlyName*' )
{
return Get-ChildItem cert:\$storeLocationPath\$storeNamePath\* | Where-Object { $_.FriendlyName -eq $FriendlyName }
}
Write-Error "Unknown parameter set '$($pscmdlet.ParameterSetName)'."
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-CertificateStore
{
<#
.SYNOPSIS
Gets an `X509CertificateStore` object for the given location and store name.
.DESCRIPTION
Returns an `X509Store` for a given store location and store name. The store must exist. Before being retured, it is opened for writing. If you don't have permission to write to the store, you'll get an error.
If you just want to read a store, we recommend using PowerShell's `cert:` drive.
.OUTPUTS
Security.Cryptography.X509Certificates.X509Store.
.EXAMPLE
Get-CertificateStore -StoreLocation LocalMachine -StoreName My
Get the local computer's Personal certificate store.
.EXAMPLE
Get-CertificateStore -StoreLocation CurrentUser -StoreName Root
Get the current user's Trusted Root Certification Authorities certificate store.
#>
[CmdletBinding(DefaultParameterSetName='ByStoreName')]
param(
[Parameter(Mandatory=$true)]
[Security.Cryptography.X509Certificates.StoreLocation]
# The location of the certificate store to get.
$StoreLocation,
[Parameter(Mandatory=$true,ParameterSetName='ByStoreName')]
[Security.Cryptography.X509Certificates.StoreName]
# The name of the certificate store to get.
$StoreName,
[Parameter(Mandatory=$true,ParameterSetName='ByCustomStoreName')]
[string]
# The name of the non-standard certificate store to get. Use this to pull certificates from a non-standard store.
$CustomStoreName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSCmdlet.ParameterSetName -eq 'ByStoreName' )
{
$store = New-Object Security.Cryptography.X509Certificates.X509Store $StoreName,$StoreLocation
}
else
{
$store = New-Object Security.Cryptography.X509Certificates.X509Store $CustomStoreName,$StoreLocation
}
$store.Open( ([Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) )
return $store
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-ComSecurityDescriptor
{
<#
.SYNOPSIS
Gets a WMI Win32_SecurityDescriptor default security or security limits object for COM Access or Launch and Activation permissions.
.DESCRIPTION
There are four available security descriptors. Default security and security limits for Access Permissions and Launch and Activation Permissions. This method returns a Win32_SecurityDescriptor for the given area and security type.
The `AsComAccessRule` parameter will return a `Carbon.Security.ComAccessRule` object for each of the access control entries in the security descriptor's ACL.
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/aa394402.aspx
.LINK
Get-ComPermission
.EXAMPLE
Get-ComSecurityDescriptor -Access -Default
Gets the default security descriptor for COM Access Permissions.
.EXAMPLE
Get-ComSecurityDescriptor -Access -Limits
Gets the security limits descriptor for COM Access Permissions.
.EXAMPLE
Get-ComSecurityDescriptor -LaunchAndActivation -Default
Gets the default security descriptor for COM Launch and Activation Permissions.
.EXAMPLE
Get-ComSecurityDescriptor -LaunchAndActivation -Limits
Gets the security limits descriptor for COM Launch and Activation Permissions.
.EXAMPLE
Get-ComSecurityDescriptor -Access -Default -AsComAccessRule
Returns a `Carbon.Security.ComAccessRule` object for each of the access control entries in the Access Permissions's default security descriptor.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermission')]
[Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestriction')]
[Switch]
# Returns a securty descriptor for one of the Access Permissions security types.
$Access,
[Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermission')]
[Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestriction')]
[Switch]
# Returns a security descriptor for one of the Launch and Activation Permissions security types.
$LaunchAndActivation,
[Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermission')]
[Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermission')]
[Switch]
# Returns the default security descriptor.
$Default,
[Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestriction')]
[Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestriction')]
[Switch]
# Returns the security limits descriptor.
$Limits,
[Switch]
# Returns `Carbon.Security.ComAccessRule` objects instead of a security descriptor.
$AsComAccessRule
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$regValueName = $pscmdlet.ParameterSetName
$bytes = Get-RegistryKeyValue -Path $ComRegKeyPath -Name $regValueName
$converter = New-Object Management.ManagementClass 'Win32_SecurityDescriptorHelper'
if( -not $bytes -and $pscmdlet.ParameterSetName -eq 'DefaultAccessPermission')
{
Write-Warning "COM Default Access Permission not found. Using reverse-engineered, hard-coded default access permissions."
# If no custom access permissions have been granted, then the DefaultAccessPermission registry value doesn't exist.
# This is the SDDL for the default permissions used on Windows 2008 and Windows 7.
$DEFAULT_SDDL = 'O:BAG:BAD:(A;;CCDCLC;;;PS)(A;;CCDC;;;SY)(A;;CCDCLC;;;BA)'
$sd = $converter.SDDLToWin32SD( $DEFAULT_SDDL )
}
else
{
$sd = $converter.BinarySDToWin32SD( $bytes )
}
if( $AsComAccessRule )
{
$sd.Descriptor.DACL |
ForEach-Object {
$identity = New-Object Security.Principal.NTAccount $_.Trustee.Domain,$_.Trustee.Name
$rights = [Carbon.Security.ComAccessRights]$_.AccessMask
$controlType = [Security.AccessControl.AccessControlType]$_.AceType
New-Object Carbon.Security.ComAccessRule $identity,$rights,$controlType
}
}
else
{
$sd.Descriptor
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-DscError
{
<#
.SYNOPSIS
Gets DSC errors from a computer's event log.
.DESCRIPTION
The DSC Local Configuration Manager (LCM) writes any errors it encounters to the `Microsoft-Windows-DSC/Operational` event log, in addition to some error messages that report that encountered an error. This function gets just the important error log messages, skipping the superflous ones that won't help you track down where the problem is.
By default, errors on the local computer are returned. You can return errors from another computer via the `ComputerName` parameter.
You can filter the results further with the `StartTime` and `EndTime` parameters. `StartTime` will return entries after the given time. `EndTime` will return entries before the given time.
If no items are found, nothing is returned.
It can take several seconds for event log entries to get written to the log, so you might not get results back. If you want to wait for entries to come back, use the `-Wait` switch. You can control how long to wait (in seconds) via the `WaitTimeoutSeconds` parameter. The default is 10 seconds.
When getting errors on a remote computer, that computer must have Remote Event Log Management firewall rules enabled. To enable them, run
Get-FirewallRule -Name '*Remove Event Log Management*' |
ForEach-Object { netsh advfirewall firewall set rule name= $_.Name new enable=yes }
`Get-DscError` is new in Carbon 2.0.
.OUTPUTS
System.Diagnostics.Eventing.Reader.EventLogRecord
.LINK
Write-DscError
.EXAMPLE
Get-DscWinEvent
Demonstrates how to get all the DSC errors from the local computer.
.EXAMPLE
Get-DscError -ComputerName 10.1.2.3
Demonstrates how to get all the DSC errors from a specific computer.
.EXAMPLE
Get-DscError -StartTime '8/1/2014 0:00'
Demonstrates how to get errors that occurred *after* a given time.
.EXAMPLE
Get-DscError -EndTime '8/30/2014 11:59:59'
Demonstrates how to get errors that occurred *before* a given time.
.EXAMPLE
Get-DscError -StartTime '8/1/2014 2:58 PM' -Wait -WaitTimeoutSeconds 5
Demonstrates how to wait for entries that match the specified criteria to appear in the event log. It can take several seconds between the time a log entry is written to when you can read it.
#>
[CmdletBinding(DefaultParameterSetName='NoWait')]
[OutputType([Diagnostics.Eventing.Reader.EventLogRecord])]
param(
[string[]]
# The computer whose DSC errors to return.
$ComputerName,
[DateTime]
# Get errors that occurred after this date/time.
$StartTime,
[DateTime]
# Get errors that occurred before this date/time.
$EndTime,
[Parameter(Mandatory=$true,ParameterSetName='Wait')]
[Switch]
# Wait for entries to appear, as it can sometimes take several seconds for entries to get written to the event log.
$Wait,
[Parameter(ParameterSetName='Wait')]
[uint32]
# The time to wait for entries to appear before giving up. Default is 10 seconds. There is no way to wait an infinite amount of time.
$WaitTimeoutSeconds = 10
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Get-DscWinEvent @PSBoundParameters -ID 4103 -Level ([Diagnostics.Eventing.Reader.StandardEventLevel]::Error)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-DscWinEvent
{
<#
.SYNOPSIS
Gets events from the DSC Windows event log.
.DESCRIPTION
Thie `Get-DscWinEvent` function gets log entries from the `Microsoft-Windows-DSC/Operational` event log, where the Local Configuration Manager writes events. By default, entries on the local computer are returned. You can return entries from another computer via the `ComputerName` parameter.
You can filter the results further with the `ID`, `Level`, `StartTime` and `EndTime` parameters. `ID` will get events with the specific ID. `Level` will get events at the specified level. `StartTime` will return entries after the given time. `EndTime` will return entries before the given time.
If no items are found, nothing is returned.
It can take several seconds for event log entries to get written to the log, so you might not get results back. If you want to wait for entries to come back, use the `-Wait` switch. You can control how long to wait (in seconds) via the `WaitTimeoutSeconds` parameter. The default is 10 seconds.
When getting errors on a remote computer, that computer must have Remote Event Log Management firewall rules enabled. To enable them, run
Get-FirewallRule -Name '*Remove Event Log Management*' |
ForEach-Object { netsh advfirewall firewall set rule name= $_.Name new enable=yes }
`Get-DscWinEvent` is new in Carbon 2.0.
.OUTPUTS
System.Diagnostics.Eventing.Reader.EventLogRecord
.LINK
Write-DscError
.LINK
Get-DscWinEvent
.EXAMPLE
Get-DscWinEvent
Demonstrates how to get all the DSC errors from the local computer.
.EXAMPLE
Get-DscWinEvent -ComputerName 10.1.2.3
Demonstrates how to get all the DSC errors from a specific computer.
.EXAMPLE
Get-DscWinEvent -StartTime '8/1/2014 0:00'
Demonstrates how to get errors that occurred *after* a given time.
.EXAMPLE
Get-DscWinEvent -EndTime '8/30/2014 11:59:59'
Demonstrates how to get errors that occurred *before* a given time.
.EXAMPLE
Get-DscWinEvent -StartTime '8/1/2014 2:58 PM' -Wait -WaitTimeoutSeconds 5
Demonstrates how to wait for entries that match the specified criteria to appear in the event log. It can take several seconds between the time a log entry is written to when you can read it.
.EXAMPLE
Get-DscWinEvent -Level ([Diagnostics.Eventing.Reader.StandardEventLevel]::Error)
Demonstrates how to get events at a specific level, in this case, only error level entries will be returned.
.EXAMPLE
Get-DscWinEvent -ID 4103
Demonstrates how to get events with a specific ID, in this case `4103`.
#>
[CmdletBinding(DefaultParameterSetName='NoWait')]
[OutputType([Diagnostics.Eventing.Reader.EventLogRecord])]
param(
[string[]]
# The computer whose DSC errors to return.
$ComputerName,
[int]
# The event ID. Only events with this ID will be returned.
$ID,
[int]
# The level. Only events at this level will be returned.
$Level,
[DateTime]
# Get errors that occurred after this date/time.
$StartTime,
[DateTime]
# Get errors that occurred before this date/time.
$EndTime,
[Parameter(Mandatory=$true,ParameterSetName='Wait')]
[Switch]
# Wait for entries to appear, as it can sometimes take several seconds for entries to get written to the event log.
$Wait,
[Parameter(ParameterSetName='Wait')]
[uint32]
# The time to wait for entries to appear before giving up. Default is 10 seconds. There is no way to wait an infinite amount of time.
$WaitTimeoutSeconds = 10
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$filter = @{
LogName = 'Microsoft-Windows-DSC/Operational';
}
if( $ID )
{
$filter['ID'] = $ID
}
if( $Level )
{
$filter['Level'] = $Level
}
if( $StartTime )
{
$filter['StartTime'] = $StartTime
}
if( $EndTime )
{
$filter['EndTime'] = $EndTime
}
function Invoke-GetWinEvent
{
param(
[string]
$ComputerName
)
Set-StrictMode -Version 'Latest'
$startedAt = Get-Date
$computerNameParam = @{ }
if( $ComputerName )
{
$computerNameParam['ComputerName'] = $ComputerName
}
try
{
$events = @()
while( -not ($events = Get-WinEvent @computerNameParam -FilterHashtable $filter -ErrorAction Ignore -Verbose:$false) )
{
if( $PSCmdlet.ParameterSetName -ne 'Wait' )
{
break
}
Start-Sleep -Milliseconds 100
[timespan]$duration = (Get-Date) - $startedAt
if( $duration.TotalSeconds -gt $WaitTimeoutSeconds )
{
break
}
}
return $events
}
catch
{
if( $_.Exception.Message -eq 'The RPC server is unavailable' )
{
Write-Error -Message ("Unable to connect to '{0}': it looks like Remote Event Log Management isn't running or is blocked by the computer's firewall. To allow this traffic through the firewall, run the following command on '{0}':`n`tGet-FirewallRule -Name '*Remove Event Log Management*' |`n`t`t ForEach-Object {{ netsh advfirewall firewall set rule name= `$_.Name new enable=yes }}." -f $ComputerName)
}
else
{
Write-Error -Exception $_.Exception
}
}
}
if( $ComputerName )
{
$ComputerName = $ComputerName |
Where-Object {
# Get just the computers that exist.
if( (Test-Connection -ComputerName $ComputerName -Quiet) )
{
return $true
}
else
{
Write-Error -Message ('Computer ''{0}'' not found.' -f $ComputerName)
return $false
}
}
if( -not $ComputerName )
{
return
}
$ComputerName | ForEach-Object { Invoke-GetWinEvent -ComputerName $_ }
}
else
{
Invoke-GetWinEvent
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-FirewallRule
{
<#
.SYNOPSIS
Gets the local computer's firewall rules.
.DESCRIPTION
Returns a `Carbon.Firewall.Rule` object for each firewall rule on the local computer.
This data is parsed from the output of:
netsh advfirewall firewall show rule name=all.
You can return specific rule(s) using the `Name` or `LiteralName` parameters. The `Name` parameter accepts wildcards; `LiteralName` does not. There can be multiple firewall rules with the same name.
If the firewall isn't configurable/running, writes an error and returns without returning any objects.
.OUTPUTS
Carbon.Firewall.Rule.
.LINK
Assert-FirewallConfigurable
.LINK
Carbon_FirewallRule
.EXAMPLE
Get-FirewallRule
Demonstrates how to get the firewall rules running on the current computer.
.EXAMPLE
Get-FirewallRule -Name 'World Wide Web Services (HTTP Traffic-In)'
Demonstrates how to get a specific rule.
.EXAMPLE
Get-FirewallRule -Name '*HTTP*'
Demonstrates how to use wildcards to find rules whose names match a wildcard pattern, in this case any rule whose name contains the text 'HTTP' is returned.
.EXAMPLE
Get-FirewallRule -LiteralName 'Custom Rule **CREATED BY AUTOMATED PROCES'
Demonstrates how to find a specific firewall rule by name if that name has wildcard characters in it.
#>
[CmdletBinding(DefaultParameterSetName='All')]
[OutputType([Carbon.Firewall.Rule])]
param(
[Parameter(Mandatory=$true,ParameterSetName='ByName')]
[string]
# The name of the rule. Wildcards supported. Names aren't unique, so you may still get back multiple rules
$Name,
[Parameter(Mandatory=$true,ParameterSetName='ByLiteralName')]
[string]
# The literal name of the rule. Wildcards not supported.
$LiteralName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Assert-FirewallConfigurable) )
{
return
}
$containsWildcards = $false
$nameArgValue = 'all'
if( $PSCmdlet.ParameterSetName -eq 'ByName' )
{
$containsWildcards = [Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name)
if( -not $containsWildcards )
{
$nameArgValue = $Name
}
}
elseif( $PSCmdlet.ParameterSetName -eq 'ByLiteralName' )
{
$nameArgValue = $LiteralName
}
# Don't change/move this. It's so we can detect if we've parsed a rule.
$rule = $null
$fieldMap = @{
'Rule name' = 'Name';
'Enabled' = 'Enabled';
'Direction' = 'Direction';
'Profiles' = 'Profiles';
'Grouping' = 'Grouping';
'LocalIP' = 'LocalIPAddress';
'RemoteIP' = 'RemoteIPAddress';
'Protocol' = 'Protocol';
'LocalPort' = 'LocalPort';
'RemotePort' = 'RemotePort';
'Edge traversal' = 'EdgeTraversal';
'InterfaceTypes' = 'InterfaceType';
'Security' = 'Security';
'Rule source' = 'Source';
'Action' = 'Action';
'Description' = 'Description';
'Program' = 'Program';
'Service' = 'Service';
}
$parsingProtocolTypeCode = $false
netsh advfirewall firewall show rule name=$nameArgValue verbose | ForEach-Object {
$line = $_
Write-Verbose $line
if( -not $line -and $rule )
{
$profiles = [Carbon.Firewall.RuleProfile]::Any
$rule.Profiles -split ',' | ForEach-Object { $profiles = $profiles -bor ([Carbon.Firewall.RuleProfile]$_) }
$constructorArgs = @(
$rule.Name,
$rule.Enabled,
$rule.Direction,
$profiles,
$rule.Grouping,
$rule.LocalIPAddress,
$rule.LocalPort,
$rule.RemoteIPAddress,
$rule.RemotePort,
$rule.Protocol,
$rule.EdgeTraversal,
$rule.Action,
$rule.InterfaceType,
$rule.Security,
$rule.Source,
$rule.Description,
$rule.Program,
$rule.Service
)
New-Object -TypeName 'Carbon.Firewall.Rule' -ArgumentList $constructorArgs
return
}
if( $line -match '^ +Type +Code *$' )
{
$parsingProtocolTypeCode = $true
return
}
if( $parsingProtocolTypeCode )
{
$parsingProtocolTypeCode = $false
if( $line -notmatch '^ +?([^ ]+) +?([^ ]+) *$' )
{
Write-Warning ('Failed to parse protocol type/code for rule {0}' -f $rule.Name)
return
}
$rule.Protocol = '{0}:{1},{2}' -f $rule.Protocol,$Matches[1],$Matches[2]
}
if( $line -notmatch '^([^:]+): +(.*)$' )
{
return
}
$propName = $matches[1]
$value = $matches[2]
if( -not $fieldMap.ContainsKey( $propName ) )
{
Write-Warning ('Unknown field ''{0}'' for rule ''{1}'' in `netsh advfirewall firewall show rule` output.' -f $propName,$rule.Name)
return
}
$propName = $fieldMap[$propName]
if( $propName -eq 'Name' )
{
$rule = New-Object 'PsObject'
foreach( $item in $fieldMap.Values )
{
Add-Member -InputObject $rule -MemberType NoteProperty -Name $item -Value $null
}
$rule.InterfaceType = [Carbon.Firewall.RuleInterfaceType]::Any
$rule.Security = [Carbon.Firewall.RuleSecurity]::NotRequired
}
if( $propName -eq 'Enabled' )
{
$value = if( $value -eq 'No' ) { $false } else { $value }
$value = if( $value -eq 'Yes' ) { $true } else { $value }
}
$rule.$propName = $value
} |
Where-Object {
-not $containsWildcards -or $_.Name -like $Name
}
}
Set-Alias -Name 'Get-FirewallRules' -Value 'Get-FirewallRule'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-Group
{
<#
.SYNOPSIS
Gets *local* groups.
.DESCRIPTION
`Get-Group` gets all *local* groups or a specific group by its name.
The objects returned, `DirectoryServices.AccountManagement.GroupPrincipal`, use external resources, which means they don't clean up propertly when garbage collected, resulting in memory leaks. You should call `Dispose()` on the objects you receieve from this function when you're done using them so these external resources can be cleaned up correctly.
`Get-Group` is new in Carbon 2.0.
.OUTPUTS
System.DirectoryServices.AccountManagement.GroupPrincipal.
.LINK
Get-User
.EXAMPLE
Get-Group
Demonstrates how to get all local groups.
.EXAMPLE
Get-Group -Name RebelAlliance
Demonstrates how to get a specific group.
#>
[CmdletBinding()]
[OutputType([DirectoryServices.AccountManagement.GroupPrincipal])]
param(
[string]
# The name of the group to return.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$ctx = New-Object 'DirectoryServices.AccountManagement.PrincipalContext' ([DirectoryServices.AccountManagement.ContextType]::Machine)
if( $Name )
{
$group = [DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity( $ctx, $Name )
if( -not $group )
{
try
{
Write-Error ('Local group ''{0}'' not found.' -f $Name) -ErrorAction:$ErrorActionPreference
return
}
finally
{
$ctx.Dispose()
}
}
return $group
}
else
{
$query = New-Object 'DirectoryServices.AccountManagement.GroupPrincipal' $ctx
$searcher = New-Object 'DirectoryServices.AccountManagement.PrincipalSearcher' $query
try
{
$searcher.FindAll()
}
finally
{
$searcher.Dispose()
$query.Dispose()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-HttpUrlAcl
{
<#
.SYNOPSIS
Gets HTTP URL security information.
.DESCRIPTION
The `Get-HttpUrlAcl` functions uses the HTTP Server API to get HTTP URL ACL information. With no parameters, it returns `Carbon.Security.HttpUrlSecurity` objects for all the HTTP URL ACLs. To get a specific HTTP URL ACL, use the `Name` parameter (wildcards supported).
[The HTTP Server API](https://msdn.microsoft.com/en-us/library/aa364510.aspx)
> enables applications to communicate over HTTP without using Microsoft Internet Information Server (IIS). Applications can register to receive HTTP requests for particular URLs, receive HTTP requests, and send HTTP responses.
An application that uses the HTTP Server API must register all URLs it listens (i.e. binds, registers) to. When registering, the user who will listen to the URL must also be provided. Typically, this is done with the `netsh http (show|add|remove) urlacl` command(s). This function replaces the `netsh http show urlacl` command.
`Get-HttpUrlAcl` was introduced in Carbon 2.1.0.
.LINK
https://msdn.microsoft.com/en-us/library/aa364510.aspx
.LINK
Grant-HttpUrlPermission
.LINK
Revoke-HttpUrlPermission
.OUTPUTS
Carbon.Security.HttpUrlSecurity.
.EXAMPLE
Get-HttpUrlAcl
Demonstrates how to get security information for all HTTP URLs configured on the current computer.
.EXAMPLE
Get-HttpUrlAcl -Url 'http://+:8594/'
Demonstrates how to get security information for a specific HTTP URL.
.EXAMPLE
Get-HttpUrlAcl -Url 'htt://*:8599/'
Demonstrates how to use wildcards to find security information. In this case, all URLs that use port 8599 will be returned.
When using wildcards, it is important that your URL end with a slash! The HTTP Server API adds a forward slash to the end of all its URLs.
.EXAMPLE
Get-HttpUrlAcl -LiteralUrl 'http://*:8599/'
Demonstrates how to use a literal URL to find security information. Will only return the ACL for the URL `http://*:8599/`.
#>
[CmdletBinding(DefaultParameterSetName='AllUrls')]
[OutputType([Carbon.Security.HttpUrlSecurity])]
param(
[Parameter(ParameterSetName='ByWildcardUrl')]
[string]
# The URL whose security information to get. Wildcards supported.
#
# Make sure your URL ends with a forward slash.
$Url,
[Parameter(ParameterSetName='ByLiteralUrl')]
[string]
# The literal URL whose security information to get.
#
# Make sure your URL ends with a forward slash.
$LiteralUrl
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$errorActionParam = @{ 'ErrorAction' = $ErrorActionPreference }
if( $ErrorActionPreference -eq 'Ignore' )
{
$ErrorActionPreference = 'SilentlyContinue'
}
$acls = @()
[Carbon.Security.HttpUrlSecurity]::GetHttpUrlSecurity() |
Where-Object {
if( $PSCmdlet.ParameterSetName -eq 'AllUrls' )
{
return $true
}
if( $PSCmdlet.ParameterSetName -eq 'ByWildcardUrl' )
{
Write-Debug -Message ('{0} -like {1}' -f $_.Url,$Url)
return $_.Url -like $Url
}
Write-Debug -Message ('{0} -eq {1}' -f $_.Url,$LiteralUrl)
return $_.Url -eq $LiteralUrl
} |
Tee-Object -Variable 'acls'
if( -not $acls )
{
if( $PSCmdlet.ParameterSetName -eq 'ByLiteralUrl' )
{
Write-Error ('HTTP ACL for URL {0} not found. The HTTP API adds a trailing forward slash (/) to the end of all URLs. Make sure your URL ends with a trailing slash.' -f $LiteralUrl) @errorActionParam
}
elseif( -not [Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Url) )
{
Write-Error ('HTTP ACL for URL {0} not found. The HTTP API adds a trailing forward slash (/) to the end of all URLs. Make sure your URL ends with a trailing slash.' -f $Url) @errorActionParam
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IdentityPrincipalContext
{
<#
.SYNOPSIS
**INTERNAL.** Do not use.
.DESCRIPTION
**INTERNAL.** Do not use.
.EXAMPLE
**INTERNAL.** Do not use.
#>
[CmdletBinding()]
[OutputType([DirectoryServices.AccountManagement.PrincipalContext])]
param(
[Parameter(Mandatory=$true)]
[Carbon.Identity]
# The identity whose principal context to get.
$Identity
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
# First, check for a local match
$machineCtx = New-Object 'DirectoryServices.AccountManagement.PrincipalContext' 'Machine',$env:COMPUTERNAME
if( [DirectoryServices.AccountManagement.Principal]::FindByIdentity( $machineCtx, 'Sid', $Identity.Sid.Value ) )
{
return $machineCtx
}
$domainCtx = New-Object 'DirectoryServices.AccountManagement.PrincipalContext' 'Domain',$Identity.Domain
if( [DirectoryServices.AccountManagement.PRincipal]::FindByIdentity( $domainCtx, 'Sid', $Identity.Sid.Value ) )
{
return $domainCtx
}
Write-Error -Message ('Unable to determine if principal ''{0}'' (SID: {1}; Type: {2}) is a machien or domain principal.' -f $Identity.FullName,$Identity.Sid.Value,$Identity.Type)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IisApplication
{
<#
.SYNOPSIS
Gets an IIS application as an `Application` object.
.DESCRIPTION
Uses the `Microsoft.Web.Administration` API to get an IIS application object. If the application doesn't exist, `$null` is returned.
The objects returned have two dynamic properties and one dynamic methods added.
* `ServerManager { get; }` - The `ServerManager` object which created the `Application` object.
* `CommitChanges()` - Persists any configuration changes made to the object back into IIS's configuration files.
* `PhysicalPath { get; }` - The physical path to the application.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.OUTPUTS
Microsoft.Web.Administration.Application.
.EXAMPLE
Get-IisApplication -SiteName 'DeathStar`
Gets all the applications running under the `DeathStar` website.
.EXAMPLE
Get-IisApplication -SiteName 'DeathStar' -VirtualPath '/'
Demonstrates how to get the main application for a website: use `/` as the application name.
.EXAMPLE
Get-IisApplication -SiteName 'DeathStar' -VirtualPath 'MainPort/ExhaustPort'
Demonstrates how to get a nested application, i.e. gets the application at `/MainPort/ExhaustPort` under the `DeathStar` website.
#>
[CmdletBinding()]
[OutputType([Microsoft.Web.Administration.Application])]
param(
[Parameter(Mandatory=$true)]
[string]
# The site where the application is running.
$SiteName,
[Parameter()]
[Alias('Name')]
[string]
# The name of the application. Default is to return all applications running under the website `$SiteName`.
$VirtualPath
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$site = Get-IisWebsite -SiteName $SiteName
if( -not $site )
{
return
}
$site.Applications |
Where-Object {
if( $VirtualPath )
{
return ($_.Path -eq "/$VirtualPath")
}
return $true
} |
Add-IisServerManagerMember -ServerManager $site.ServerManager -PassThru
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IisAppPool
{
<#
.SYNOPSIS
Gets a `Microsoft.Web.Administration.ApplicationPool` object for an application pool.
.DESCRIPTION
The `Get-IisAppPool` function returns an IIS application pools as a `Microsoft.Web.Administration.ApplicationPool` object. Use the `Name` parameter to return the application pool. If that application pool isn't found, `$null` is returned.
Carbon adds a `CommitChanges` method on each object returned that you can use to save configuration changes.
Beginning in Carbon 2.0, `Get-IisAppPool` will return all application pools installed on the current computer.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
http://msdn.microsoft.com/en-us/library/microsoft.web.administration.applicationpool(v=vs.90).aspx
.OUTPUTS
Microsoft.Web.Administration.ApplicationPool.
.EXAMPLE
Get-IisAppPool
Demonstrates how to get *all* application pools.
.EXAMPLE
Get-IisAppPool -Name 'Batcave'
Gets the `Batcave` application pool.
.EXAMPLE
Get-IisAppPool -Name 'Missing!'
Returns `null` since, for purposes of this example, there is no `Missing~` application pool.
#>
[CmdletBinding()]
[OutputType([Microsoft.Web.Administration.ApplicationPool])]
param(
[string]
# The name of the application pool to return. If not supplied, all application pools are returned.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$mgr = New-Object Microsoft.Web.Administration.ServerManager
$mgr.ApplicationPools |
Where-Object {
if( -not $PSBoundParameters.ContainsKey('Name') )
{
return $true
}
return $_.Name -eq $Name
} |
Add-IisServerManagerMember -ServerManager $mgr -PassThru
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IisConfigurationSection
{
<#
.SYNOPSIS
Gets a Microsoft.Web.Adminisration configuration section for a given site and path.
.DESCRIPTION
Uses the Microsoft.Web.Administration API to get a `Microsoft.Web.Administration.ConfigurationSection`.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.OUTPUTS
Microsoft.Web.Administration.ConfigurationSection.
.EXAMPLE
Get-IisConfigurationSection -SiteName Peanuts -Path Doghouse -Path 'system.webServer/security/authentication/anonymousAuthentication'
Returns a configuration section which represents the Peanuts site's Doghouse path's anonymous authentication settings.
#>
[CmdletBinding(DefaultParameterSetName='Global')]
[OutputType([Microsoft.Web.Administration.ConfigurationSection])]
param(
[Parameter(Mandatory=$true,ParameterSetName='ForSite')]
[string]
# The site where anonymous authentication should be set.
$SiteName,
[Parameter(ParameterSetName='ForSite')]
[Alias('Path')]
[string]
# The optional site path whose configuration should be returned.
$VirtualPath = '',
[Parameter(Mandatory=$true,ParameterSetName='ForSite')]
[Parameter(Mandatory=$true,ParameterSetName='Global')]
[string]
# The path to the configuration section to return.
$SectionPath,
[Type]
# The type of object to return. Optional.
$Type = [Microsoft.Web.Administration.ConfigurationSection]
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$mgr = New-Object 'Microsoft.Web.Administration.ServerManager'
$config = $mgr.GetApplicationHostConfiguration()
$section = $null
$qualifier = ''
try
{
if( $PSCmdlet.ParameterSetName -eq 'ForSite' )
{
$qualifier = Join-IisVirtualPath $SiteName $VirtualPath
$section = $config.GetSection( $SectionPath, $Type, $qualifier )
}
else
{
$section = $config.GetSection( $SectionPath, $Type )
}
}
catch
{
}
if( $section )
{
$section | Add-IisServerManagerMember -ServerManager $mgr -PassThru
}
else
{
Write-Error ('IIS:{0}: configuration section {1} not found.' -f $qualifier,$SectionPath)
return
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IisHttpHeader
{
<#
.SYNOPSIS
Gets the HTTP headers for a website or directory under a website.
.DESCRIPTION
For each custom HTTP header defined under a website and/or a sub-directory under a website, returns a `Carbon.Iis.HttpHeader` object. This object has two properties:
* Name: the name of the HTTP header
* Value: the value of the HTTP header
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.OUTPUTS
Carbon.Iis.HttpHeader.
.LINK
Set-IisHttpHeader
.EXAMPLE
Get-IisHttpHeader -SiteName SopwithCamel
Returns the HTTP headers for the `SopwithCamel` website.
.EXAMPLE
Get-IisHttpHeader -SiteName SopwithCamel -Path Engine
Returns the HTTP headers for the `Engine` directory under the `SopwithCamel` website.
.EXAMPLE
Get-IisHttpHeader -SiteName SopwithCambel -Name 'X-*'
Returns all HTTP headers which match the `X-*` wildcard.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the website whose headers to return.
$SiteName,
[Alias('Path')]
[string]
# The optional path under `SiteName` whose headers to return.
$VirtualPath = '',
[string]
# The name of the HTTP header to return. Optional. If not given, all headers are returned. Wildcards supported.
$Name = '*'
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$httpProtocol = Get-IisConfigurationSection -SiteName $SiteName `
-VirtualPath $VirtualPath `
-SectionPath 'system.webServer/httpProtocol'
$httpProtocol.GetCollection('customHeaders') |
Where-Object { $_['name'] -like $Name } |
ForEach-Object { New-Object Carbon.Iis.HttpHeader $_['name'],$_['value'] }
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IisHttpRedirect
{
<#
.SYNOPSIS
Gets the HTTP redirect settings for a website or virtual directory/application under a website.
.DESCRIPTION
Returns a `Carbon.Iis.HttpRedirectConfigurationSection` object for the given HTTP redirect settings. The object contains the following properties:
* Enabled - `True` if the redirect is enabled, `False` otherwise.
* Destination - The URL where requests are directed to.
* HttpResponseCode - The HTTP status code sent to the browser for the redirect.
* ExactDestination - `True` if redirects are to destination, regardless of the request path. This will send all requests to `Destination`.
* ChildOnly - `True` if redirects are only to content in the destination directory (not subdirectories).
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
http://www.iis.net/configreference/system.webserver/httpredirect
.OUTPUTS
Carbon.Iis.HttpRedirectConfigurationSection.
.EXAMPLE
Get-IisHttpRedirect -SiteName ExampleWebsite
Gets the redirect settings for ExampleWebsite.
.EXAMPLE
Get-IisHttpRedirect -SiteName ExampleWebsite -Path MyVirtualDirectory
Gets the redirect settings for the MyVirtualDirectory virtual directory under ExampleWebsite.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The site's whose HTTP redirect settings will be retrieved.
$SiteName,
[Alias('Path')]
[string]
# The optional path to a sub-directory under `SiteName` whose settings to return.
$VirtualPath = ''
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Get-IisConfigurationSection -SiteName $SiteName `
-VirtualPath $VirtualPath `
-SectionPath 'system.webServer/httpRedirect' `
-Type ([Carbon.Iis.HttpRedirectConfigurationSection])
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IisMimeMap
{
<#
.SYNOPSIS
Gets the file extension to MIME type mappings.
.DESCRIPTION
IIS won't serve static content unless there is an entry for it in the web server or website's MIME map configuration. This function will return all the MIME maps for the current server. The objects returned are instances of the `Carbon.Iis.MimeMap` class, and contain the following properties:
* `FileExtension`: the mapping's file extension
* `MimeType`: the mapping's MIME type
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.OUTPUTS
Carbon.Iis.MimeMap.
.LINK
Set-IisMimeMap
.EXAMPLE
Get-IisMimeMap
Gets all the the file extension to MIME type mappings for the web server.
.EXAMPLE
Get-IisMimeMap -FileExtension .htm*
Gets all the file extension to MIME type mappings whose file extension matches the `.htm*` wildcard.
.EXAMPLE
Get-IisMimeMap -MimeType 'text/*'
Gets all the file extension to MIME type mappings whose MIME type matches the `text/*` wildcard.
.EXAMPLE
Get-IisMimeMap -SiteName DeathStar
Gets all the file extenstion to MIME type mappings for the `DeathStar` website.
.EXAMPLE
Get-IisMimeMap -SiteName DeathStar -VirtualPath ExhaustPort
Gets all the file extension to MIME type mappings for the `DeathStar`'s `ExhausePort` directory.
#>
[CmdletBinding(DefaultParameterSetName='ForWebServer')]
[OutputType([Carbon.Iis.MimeMap])]
param(
[Parameter(Mandatory=$true,ParameterSetName='ForWebsite')]
[string]
# The website whose MIME mappings to return. If not given, returns the web server's MIME map.
$SiteName,
[Parameter(ParameterSetName='ForWebsite')]
[Alias('Path')]
[string]
# The directory under the website whose MIME mappings to return. Optional.
$VirtualPath = '',
[string]
# The name of the file extensions to return. Wildcards accepted.
$FileExtension = '*',
[string]
# The name of the MIME type(s) to return. Wildcards accepted.
$MimeType = '*'
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$getIisConfigSectionParams = @{ }
if( $PSCmdlet.ParameterSetName -eq 'ForWebsite' )
{
$getIisConfigSectionParams['SiteName'] = $SiteName
$getIisConfigSectionParams['VirtualPath'] = $VirtualPath
}
$staticContent = Get-IisConfigurationSection -SectionPath 'system.webServer/staticContent' @getIisConfigSectionParams
$staticContent.GetCollection() |
Where-Object { $_['fileExtension'] -like $FileExtension -and $_['mimeType'] -like $MimeType } |
ForEach-Object {
New-Object 'Carbon.Iis.MimeMap' ($_['fileExtension'],$_['mimeType'])
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IisSecurityAuthentication
{
<#
.SYNOPSIS
Gets a site's (and optional sub-directory's) security authentication configuration section.
.DESCRIPTION
You can get the anonymous, basic, digest, and Windows authentication sections by using the `Anonymous`, `Basic`, `Digest`, or `Windows` switches, respectively.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.OUTPUTS
Microsoft.Web.Administration.ConfigurationSection.
.EXAMPLE
Get-IisSecurityAuthentication -SiteName Peanuts -Anonymous
Gets the `Peanuts` site's anonymous authentication configuration section.
.EXAMPLE
Get-IisSecurityAuthentication -SiteName Peanuts -VirtualPath Doghouse -Basic
Gets the `Peanuts` site's `Doghouse` sub-directory's basic authentication configuration section.
#>
[CmdletBinding()]
[OutputType([Microsoft.Web.Administration.ConfigurationSection])]
param(
[Parameter(Mandatory=$true)]
[string]
# The site where anonymous authentication should be set.
$SiteName,
[Alias('Path')]
[string]
# The optional path where anonymous authentication should be set.
$VirtualPath = '',
[Parameter(Mandatory=$true,ParameterSetName='anonymousAuthentication')]
[Switch]
# Gets a site's (and optional sub-directory's) anonymous authentication configuration section.
$Anonymous,
[Parameter(Mandatory=$true,ParameterSetName='basicAuthentication')]
[Switch]
# Gets a site's (and optional sub-directory's) basic authentication configuration section.
$Basic,
[Parameter(Mandatory=$true,ParameterSetName='digestAuthentication')]
[Switch]
# Gets a site's (and optional sub-directory's) digest authentication configuration section.
$Digest,
[Parameter(Mandatory=$true,ParameterSetName='windowsAuthentication')]
[Switch]
# Gets a site's (and optional sub-directory's) Windows authentication configuration section.
$Windows
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$sectionPath = 'system.webServer/security/authentication/{0}' -f $pscmdlet.ParameterSetName
Get-IisConfigurationSection -SiteName $SiteName -VirtualPath $VirtualPath -SectionPath $sectionPath
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IisVersion
{
<#
.SYNOPSIS
Gets the version of IIS.
.DESCRIPTION
Reads the version of IIS from the registry, and returns it as a `Major.Minor` formatted string.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Get-IisVersion
Returns `7.0` on Windows 2008, and `7.5` on Windows 7 and Windows 2008 R2.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$props = Get-ItemProperty hklm:\Software\Microsoft\InetStp
return $props.MajorVersion.ToString() + "." + $props.MinorVersion.ToString()
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IisWebsite
{
<#
.SYNOPSIS
Returns all the websites installed on the local computer, or a specific website.
.DESCRIPTION
Returns a Microsoft.Web.Administration.Site object.
Each object will have a `CommitChanges` script method added which will allow you to commit/persist any changes to the website's configuration.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.OUTPUTS
Microsoft.Web.Administration.Site.
.LINK
http://msdn.microsoft.com/en-us/library/microsoft.web.administration.site.aspx
.EXAMPLE
Get-IisWebsite
Returns all installed websites.
.EXAMPLE
Get-IisWebsite -SiteName 'WebsiteName'
Returns the details for the site named `WebsiteName`.
#>
[CmdletBinding()]
[OutputType([Microsoft.Web.Administration.Site])]
param(
[string]
[Alias('SiteName')]
# The name of the site to get.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $Name -and -not (Test-IisWebsite -Name $Name) )
{
return $null
}
$mgr = New-Object 'Microsoft.Web.Administration.ServerManager'
$mgr.Sites |
Where-Object {
if( $Name )
{
$_.Name -eq $Name
}
else
{
$true
}
} | Add-IisServerManagerMember -ServerManager $mgr -PassThru
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-IPAddress
{
<#
.SYNOPSIS
Gets the IP addresses in use on the local computer.
.DESCRIPTION
The .NET API for getting all the IP addresses in use on the current computer's network intefaces is pretty cumbersome. If all you care about is getting the IP addresses in use on the current computer, and you don't care where/how they're used, use this function.
If you *do* care about network interfaces, then you'll have to do it yourself using the [System.Net.NetworkInformation.NetworkInterface](http://msdn.microsoft.com/en-us/library/System.Net.NetworkInformation.NetworkInterface.aspx) class's [GetAllNetworkInterfaces](http://msdn.microsoft.com/en-us/library/system.net.networkinformation.networkinterface.getallnetworkinterfaces.aspx) static method, e.g.
[Net.NetworkInformation.NetworkInterface]::GetNetworkInterfaces()
.LINK
http://stackoverflow.com/questions/1069103/how-to-get-my-own-ip-address-in-c
.OUTPUTS
System.Net.IPAddress.
.EXAMPLE
Get-IPAddress
Returns all the IP addresses in use on the local computer, IPv4 *and* IPv6.
.EXAMPLE
Get-IPAddress -V4
Returns just the IPv4 addresses in use on the local computer.
.EXAMPLE
Get-IPADdress -V6
Retruns just the IPv6 addresses in use on the local computer.
#>
[CmdletBinding(DefaultParameterSetName='NonFiltered')]
param(
[Parameter(ParameterSetName='Filtered')]
[Switch]
# Return just IPv4 addresses.
$V4,
[Parameter(ParameterSetName='Filtered')]
[Switch]
# Return just IPv6 addresses.
$V6
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
[Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces() |
Where-Object { $_.OperationalStatus -eq 'Up' -and $_.NetworkInterfaceType -ne 'Loopback' } |
ForEach-Object { $_.GetIPProperties() } |
Select-Object -ExpandProperty UnicastAddresses |
Select-Object -ExpandProperty Address |
Where-Object {
if( $PSCmdlet.ParameterSetName -eq 'NonFiltered' )
{
return ($_.AddressFamily -eq 'InterNetwork' -or $_.AddressFamily -eq 'InterNetworkV6')
}
if( $V4 -and $_.AddressFamily -eq 'InterNetwork' )
{
return $true
}
if( $V6 -and $_.AddressFamily -eq 'InterNetworkV6' )
{
return $true
}
return $false
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-Msi
{
<#
.SYNOPSIS
Gets details about an MSI file.
.DESCRIPTION
The `Get-Msi` function reads the installer properties from an MSI file and returns a `Carbon.Msi.MsiInfo` object representing an MSI's properties. `Carbon.Msi.MsiInfo` has properties for the following required MSI properties:
* ProductName
* ProductCode
* ProduceLanguage
* Manufacturer
* ProductVersion
All other properties are accessible via the `Properties` property, which is a hashtable of property name/value pairs.
There is an additioanl `Path` property to capture the path of the MSI the properties came from.
`Get-Msi` was introduced in Carbon 2.0.
.LINK
https://msdn.microsoft.com/en-us/library/aa370905.aspx
.EXAMPLE
Get-Msi -Path MyCool.msi
Demonstrates how to read the properties from `MyCool.msi` file.
.EXAMPLE
Get-ChildItem *.msi -Recurse | Get-Msi
Demonstrates how you can pipe file info objects into `Get-Msi`.
#>
[CmdletBinding()]
[OutputType('Carbon.Msi.MsiInfo')]
param (
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[Alias('FullName')]
[string[]]
# Path to the MSI file whose information to retrieve. Wildcards supported.
$Path
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
}
process
{
$Path |
Resolve-Path |
Select-Object -ExpandProperty 'ProviderPath' |
ForEach-Object {
$msiPath = $_
try
{
Write-Verbose ('Opening MSI {0}' -f $msiPath)
New-Object -TypeName 'Carbon.Msi.MsiInfo' -ArgumentList $msiPath
}
catch
{
$ex = $_.Exception
$errMsg = 'Failed to open MSI file ''{0}''.' -f $msiPath
if( $ex )
{
$errMsg = '{0} {1} was thrown. The exception message is: ''{2}''.' -f $errMsg,$ex.GetType().FullName,$ex.Message
if( $ex -is [Runtime.InteropServices.COMException] )
{
$errMsg = '{0} HRESULT: {1:x}. (You can look up the meaning of HRESULT values at https://msdn.microsoft.com/en-us/library/cc704587.aspx.)' -f $errMsg,$ex.ErrorCode
}
}
Write-Error -Message $errMsg
return
}
}
}
end
{
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-PathProvider
{
<#
.SYNOPSIS
Returns a path's PowerShell provider.
.DESCRIPTION
When you want to do something with a path that depends on its provider, use this function. The path doesn't have to exist.
If you pass in a relative path, it is resolved relative to the current directory. So make sure you're in the right place.
.OUTPUTS
System.Management.Automation.ProviderInfo.
.EXAMPLE
Get-PathProvider -Path 'C:\Windows'
Demonstrates how to get the path provider for an NTFS path.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The path whose provider to get.
$Path
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$pathQualifier = Split-Path -Qualifier $Path -ErrorAction SilentlyContinue
if( -not $pathQualifier )
{
$Path = Join-Path -Path (Get-Location) -ChildPath $Path
$pathQualifier = Split-Path -Qualifier $Path -ErrorAction SilentlyContinue
if( -not $pathQualifier )
{
Write-Error "Qualifier for path '$Path' not found."
return
}
}
Get-PSDrive $pathQualifier.Trim(':') |
Select-Object -ExpandProperty 'Provider'
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-PathToHostsFile
{
<#
.SYNOPSIS
Gets the path to this computer's hosts file.
.DESCRIPTION
This is a convenience method so you don't have to have the path to the hosts file hard-coded in your scripts.
.EXAMPLE
Get-PathToHostsFile
Returns `C:\Windows\system32\drivers\etc\hosts`. Uses the environment variable to find the root to the Windows directory.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
return Join-Path $env:windir system32\drivers\etc\hosts
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-PerformanceCounter
{
<#
.SYNOPSIS
Gets the performance counters for a category.
.DESCRIPTION
Returns `PerformanceCounterCategory` objects for the given category name. If not counters exist for the category exits, an empty array is returned.
.OUTPUTS
System.Diagnostics.PerformanceCounterCategory.
.EXAMPLE
Get-PerformanceCounter -CategoryName Processor
Gets all the `Processor` performance counters.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The category's name whose performance counters will be returned.
$CategoryName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( (Test-PerformanceCounterCategory -CategoryName $CategoryName) )
{
$category = New-Object Diagnostics.PerformanceCounterCategory $CategoryName
return $category.GetCounters("")
}
}
Set-Alias -Name 'Get-PerformanceCounters' -Value 'Get-PerformanceCounter'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-PowerShellModuleInstallPath
{
<#
.SYNOPSIS
Returns the path to the directory where you can install custom modules.
.DESCRIPTION
Custom modules should be installed under the `Program Files` directory. This function looks at the `PSModulePath` environment variable to find the install location under `Program Files`. If that path isn't part of the `PSModulePath` environment variable, returns the module path under `$PSHOME`. If that isn't part of the `PSModulePath` environment variable, an error is written and nothing is returned.
`Get-PowerShellModuleInstallPath` is new in Carbon 2.0.
.EXAMPLE
Get-PowerShellModuleInstallPath
Demonstrates how to get the path where modules should be installed.
#>
[CmdletBinding()]
[OutputType([string])]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$modulePaths = $env:PSModulePath -split ';'
$programFileModulePath = Join-Path -Path $env:ProgramFiles -ChildPath 'WindowsPowerShell\Modules'
$installRoot = $modulePaths |
Where-Object { $_.TrimEnd('\') -eq $programFileModulePath } |
Select-Object -First 1
if( $installRoot )
{
return $programFileModulePath
}
$psHomeModulePath = Join-Path -Path $PSHOME -ChildPath 'Modules'
$installRoot = $modulePaths |
Where-Object { $_.TrimEnd('\') -eq $psHomeModulePath } |
Select-Object -First 1
if( $installRoot )
{
return $psHomeModulePath
}
Write-Error -Message ('PSModulePaths ''{0}'' and ''{1}'' not found in the PSModulePath environment variable.' -f $programFileModulePath,$psHomeModulePath)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-PowershellPath
{
<#
.SYNOPSIS
Gets the path to powershell.exe.
.DESCRIPTION
Returns the path to the powershell.exe binary for the machine's default architecture (i.e. x86 or x64). If you're on a x64 machine and want to get the path to x86 PowerShell, set the `x86` switch.
Here are the possible combinations of operating system, PowerShell, and desired path architectures, and the path they map to.
+-----+-----+------+--------------------------------------------------------------+
| OS | PS | Path | Result |
+-----+-----+------+--------------------------------------------------------------+
| x64 | x64 | x64 | $env:windir\System32\Windows PowerShell\v1.0\powershell.exe |
| x64 | x64 | x86 | $env:windir\SysWOW64\Windows PowerShell\v1.0\powershell.exe |
| x64 | x86 | x64 | $env:windir\sysnative\Windows PowerShell\v1.0\powershell.exe |
| x64 | x86 | x86 | $env:windir\SysWOW64\Windows PowerShell\v1.0\powershell.exe |
| x86 | x86 | x64 | $env:windir\System32\Windows PowerShell\v1.0\powershell.exe |
| x86 | x86 | x86 | $env:windir\System32\Windows PowerShell\v1.0\powershell.exe |
+-----+-----+------+--------------------------------------------------------------+
.EXAMPLE
Get-PowerShellPath
Returns the path to the version of PowerShell that matches the computer's architecture (i.e. x86 or x64).
.EXAMPLE
Get-PowerShellPath -x86
Returns the path to the x86 version of PowerShell.
#>
[CmdletBinding()]
param(
[Switch]
# Gets the path to 32-bit PowerShell.
$x86
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$psPath = $PSHOME
if( Test-OSIs64Bit )
{
if( Test-PowerShellIs64Bit )
{
if( $x86 )
{
# x64 OS, x64 PS, want x86 path
$psPath = $PSHOME -replace 'System32','SysWOW64'
}
}
else
{
if( -not $x86 )
{
# x64 OS, x32 PS, want x64 path
$psPath = $PSHome -replace 'SysWOW64','sysnative'
}
}
}
else
{
# x86 OS, no SysWOW64, everything is in $PSHOME
$psPath = $PSHOME
}
Join-Path $psPath powershell.exe
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-Privilege
{
<#
.SYNOPSIS
Gets an identity's privileges.
.DESCRIPTION
These privileges are usually managed by Group Policy and control the system operations and types of logons a user/group can perform.
Note: if a computer is not on a domain, this function won't work.
.OUTPUTS
System.String
.LINK
Carbon_Privilege
.LINK
Grant-Privilege
.LINK
Revoke-Prvileges
.LINK
Test-Privilege
.EXAMPLE
Get-Privilege -Identity TheBeast
Gets `TheBeast`'s privileges as an array of strings.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The identity whose privileges to return.
$Identity
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
[Carbon.Security.Privilege]::GetPrivileges( $Identity )
}
Set-Alias -Name 'Get-Privileges' -Value 'Get-Privilege'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-ProgramInstallInfo
{
<#
.SYNOPSIS
Gets information about the programs installed on the computer.
.DESCRIPTION
The `Get-ProgramInstallInfo` function is the PowerShell equivalent of the Programs and Features UI in the Control Panel. It inspects the registry to determine what programs are installed. It will return programs installed for *all* users, not just the current user.
`Get-ProgramInstallInfo` tries its best to get accurate data. The following properties either isn't stored consistently, is in strange formats, can't be parsed, etc.
* The `ProductCode` property is set to `[Guid]::Empty` if the software doesn't have a product code.
* The `User` property will only be set for software installed for specific users. For global software, the `User` property will be `[String]::Empty`.
* The `InstallDate` property is set to `[DateTime]::MinValue` if the install date can't be determined.
* The `Version` property is `$null` if the version can't be parsed
.OUTPUTS
Carbon.Computer.ProgramInstallInfo.
.EXAMPLE
Get-ProgramInstallInfo
Demonstrates how to get a list of all the installed programs, similar to what the Programs and Features UI shows.
.EXAMPLE
Get-ProgramInstallInfo -Name 'Google Chrome'
Demonstrates how to get a specific program. If the specific program isn't found, `$null` is returned.
.EXAMPLE
Get-ProgramInstallInfo -Name 'Microsoft*'
Demonstrates how to use wildcards to search for multiple programs.
#>
[CmdletBinding()]
[OutputType([Carbon.Computer.ProgramInstallInfo])]
param(
[string]
# The name of a specific program to get. Wildcards supported.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Path -Path 'hku:\') )
{
$null = New-PSDrive -Name 'HKU' -PSProvider Registry -Root 'HKEY_USERS'
}
('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall','HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall','hku:\*\Software\Microsoft\Windows\CurrentVersion\Uninstall\*') |
Where-Object { Test-Path -Path $_ -PathType Container } |
Get-ChildItem |
Where-Object {
$valueNames = $_.GetValueNames()
[Microsoft.Win32.RegistryKey]$key = $_
if( $valueNames -notcontains 'DisplayName' )
{
Write-Debug ('Skipping {0}: DisplayName not found.' -f $_.Name)
return $false
}
$displayName = $_.GetValue( 'DisplayName' )
if( $valueNames -contains 'ParentKeyName' )
{
Write-Debug ('Skipping {0} ({1}): found ParentKeyName property.' -f $displayName,$_.Name)
return $false
}
if( $valueNames -contains 'SystemComponent' -and $_.GetValue( 'SystemComponent' ) -eq 1 )
{
Write-Debug ('Skipping {0} ({1}): SystemComponent property is 1.' -f $displayName,$_.Name)
return $false
}
return $true
} |
Where-Object {
if( $Name )
{
return $_.GetValue('DisplayName') -like $Name
}
return $true
} |
ForEach-Object { New-Object 'Carbon.Computer.ProgramInstallInfo' $_ }
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-RegistryKeyValue
{
<#
.SYNOPSIS
Gets the value from a registry key.
.DESCRIPTION
PowerShell's `Get-ItemProperty` cmdlet is a pain to use. It doesn't actually return an object representing a registry key's value, but some other weird object that requires painful gyrations to get values from. This function returns just the value of a key.
.EXAMPLE
Get-RegistryKeyValue -Path 'hklm:\Software\Carbon\Test' -Name 'Title'
Returns the value of the 'hklm:\Software\Carbon\Test' key's `Title` value.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to the registry key where the value should be set. Will be created if it doesn't exist.
$Path,
[Parameter(Mandatory=$true)]
[string]
# The name of the value being set.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-RegistryKeyValue -Path $Path -Name $Name) )
{
return $null
}
$itemProperties = Get-ItemProperty -Path $Path -Name *
$value = $itemProperties.$Name
Write-Debug -Message ('[{0}@{1}: {2} -is {3}' -f $Path,$Name,$value,$value.GetType())
return $value
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-ScheduledTask
{
<#
.SYNOPSIS
Gets the scheduled tasks for the current computer.
.DESCRIPTION
The `Get-ScheduledTask` function gets the scheduled tasks on the current computer. It returns `Carbon.TaskScheduler.TaskInfo` objects for each one.
With no parameters, `Get-ScheduledTask` returns all scheduled tasks. To get a specific scheduled task, use the `Name` parameter, which must be the full name of the task, i.e. path plus name. The name parameter accepts wildcards. If a scheduled task with the given name isn't found, an error is written.
This function has the same name as the built-in `Get-ScheduledTask` function that comes on Windows 2012/8 and later. It returns objects with the same properties, but if you want to use the built-in function, use the `ScheduledTasks` qualifier, e.g. `ScheduledTasks\Get-ScheduledTask`.
.LINK
Test-ScheduledTask
.EXAMPLE
Get-ScheduledTask
Demonstrates how to get all scheduled tasks.
.EXAMPLE
Get-ScheduledTask -Name 'AutoUpdateMyApp'
Demonstrates how to get a specific task.
.EXAMPLE
Get-ScheduledTask -Name '*Microsoft*'
Demonstrates how to get all tasks that match a wildcard pattern.
.EXAMPLE
ScheduledTasks\Get-ScheduledTask
Demonstrates how to call the `Get-ScheduledTask` function in the `ScheduledTasks` module which ships on Windows 2012/8 and later.
#>
[CmdletBinding()]
[OutputType([Carbon.TaskScheduler.TaskInfo])]
param(
[Parameter()]
[Alias('TaskName')]
[string]
# The name of the scheduled task to return. Wildcards supported. This must be the *full task name*, i.e. the task's path/location and its name.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
function ConvertFrom-RepetitionElement
{
param(
[Xml.XmlElement]
$TriggerElement
)
Set-StrictMode -Version 'Latest'
[Carbon.TaskScheduler.ScheduleType]$scheduleType = [Carbon.TaskScheduler.ScheduleType]::Unknown
$interval = $null
$modifier = $null
$duration = $null
$stopAtEnd = $false
[TimeSpan]$delay = [TimeSpan]::Zero
if( $TriggerElement.GetElementsByTagName('Repetition').Count -gt 0 )
{
$repetition = $TriggerElement.Repetition
$interval = $repetition.Interval
if( $interval -match 'PT(\d+)(.*)$' )
{
$modifier = $Matches[1]
$unit = $Matches[2]
$hour = 0
$minute = 0
$second = 0
switch( $unit )
{
'H' { $hour = $modifier }
'M' { $minute = $modifier }
}
$scheduleTypes = @{
'H' = 'Hourly';
'M' = 'Minute';
}
if( $scheduleTypes.ContainsKey( $unit ) )
{
$scheduleType = $scheduleTypes[$unit]
}
$timespan = New-Object 'TimeSpan' $hour,$minute,$second
switch( $scheduleType )
{
'Hourly' { $modifier = $timespan.TotalHours }
'Minute' { $modifier = $timespan.TotalMinutes }
}
}
if( $repetition | Get-Member -Name 'Duration' )
{
$duration = $repetition.Duration
if( $duration -match 'PT((\d+)H)?((\d+)M)?((\d+)S)?$' )
{
$hours = $Matches[2]
$minutes = $Matches[4]
$seconds = $Matches[6]
$duration = New-Object -TypeName 'TimeSpan' -ArgumentList $hours,$minutes,$seconds
}
}
if( $repetition | Get-Member -Name 'StopAtDurationEnd' )
{
$stopAtEnd = ($repetition.StopAtDurationEnd -eq 'true')
}
}
if( $TriggerElement | Get-Member -Name 'Delay' )
{
$delayExpression = $TriggerElement.Delay
if( $delayExpression -match '^PT(\d+)M(\d+)S$' )
{
$delay = New-Object 'TimeSpan' 0,$Matches[1],$Matches[2]
}
}
return $scheduleType,$modifier,$duration,$stopAtEnd,$delay
}
$optionalArgs = @()
$wildcardSearch = $false
if( $Name )
{
if( [Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name) )
{
$wildcardSearch = $true
}
else
{
$Name = Join-Path -Path '\' -ChildPath $Name
$optionalArgs = @( '/tn', $Name )
}
}
$originalErrPreference = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
$errFile = Join-Path -Path $env:TEMP -ChildPath ('Carbon+Get-ScheduledTask+{0}' -f [IO.Path]::GetRandomFileName())
[object[]]$output = schtasks /query /v /fo csv $optionalArgs 2> $errFile | ConvertFrom-Csv | Where-Object { $_.HostName -ne 'HostName' }
$ErrorActionPreference = $originalErrPreference
if( $LASTEXITCODE )
{
if( (Test-Path -Path $errFile -PathType Leaf) )
{
$error = (Get-Content -Path $errFile) -join ([Environment]::NewLine)
try
{
if( $error -like '*The system cannot find the file specified.*' )
{
Write-Error ('Scheduled task ''{0}'' not found.' -f $Name)
}
else
{
Write-Error ($error)
}
}
finally
{
Remove-Item -Path $errFile
}
}
return
}
if( -not $output )
{
return
}
for( $idx = 0; $idx -lt $output.Count; ++$idx )
{
$csvTask = $output[$idx]
$xml = schtasks /query /tn $csvTask.TaskName /xml | Where-Object { $_ }
$xml = $xml -join ([Environment]::NewLine)
$xmlDoc = [xml]$xml
$taskPath = Split-Path -Parent -Path $csvTask.TaskName
# Get-ScheduledTask on Win2012/8 has a trailing slash so we include it here.
if( $taskPath -ne '\' )
{
$taskPath = '{0}\' -f $taskPath
}
$taskName = Split-Path -Leaf -Path $csvTask.TaskName
$xmlTask = $xmlDoc.Task
$principal = $xmlTask.Principals.Principal
$isInteractive = $false
$noPassword = $false
if( $principal | Get-Member 'LogonType' )
{
$isInteractive = $principal.LogonType -eq 'InteractiveTokenOrPassword'
$noPassword = $principal.LogonType -eq 'S4U'
}
$highestRunLevel = $false
if( $principal | Get-Member 'RunLevel' )
{
$highestRunLevel = ($principal.RunLevel -eq 'HighestAvailable')
}
$createDate = [DateTime]::MinValue
if( $xmlTask | Get-Member -Name 'RegistrationInfo' )
{
$regInfo = $xmlTask.RegistrationInfo
if( $regInfo | Get-Member -Name 'Date' )
{
$createDate = [datetime]$regInfo.Date
}
}
$taskToRun = $csvTask.'Task To Run'
if( ($xmlTask | Get-Member -Name 'Actions') -and $xmlTask.Actions.ChildNodes.Count -eq 1 )
{
$actions = $xmlTask.Actions
if( ($actions | Get-Member -Name 'Exec') -and ($actions.Exec | Measure-Object | Select-Object -ExpandProperty 'Count') -eq 1)
{
$exec = $actions.Exec
if( $exec | Get-Member -Name 'Command' )
{
$taskToRun = $exec.Command
}
if( $exec | Get-Member -Name 'Arguments' )
{
$taskToRun = '{0} {1}' -f $taskToRun,$exec.Arguments
}
}
}
$ctorArgs = @(
$csvTask.HostName,
$taskPath,
$taskName,
$csvTask.'Next Run Time',
$csvTask.Status,
$csvTask.'Logon Mode',
$csvTask.'Last Run Time',
$csvTask.Author,
$createDate,
$taskToRun,
$csvTask.'Start In',
$csvTask.Comment,
$csvTask.'Scheduled Task State',
$csvTask.'Idle Time',
$csvTask.'Power Management',
$csvTask.'Run As User',
$isInteractive,
$noPassword,
$highestRunLevel,
$csvTask.'Delete Task If Not Rescheduled'
)
$task = New-Object -TypeName 'Carbon.TaskScheduler.TaskInfo' -ArgumentList $ctorArgs
$scheduleIdx = 0
while( $idx -lt $output.Count -and $output[$idx].TaskName -eq $csvTask.TaskName )
{
$csvTask = $output[$idx++]
[Carbon.TaskScheduler.ScheduleType]$scheduleType = [Carbon.TaskScheduler.ScheduleType]::Unknown
[int[]]$days = @()
[int]$csvDay = 0
if( [int]::TryParse($csvTask.Days, [ref]$csvDay) )
{
$days = @( $csvDay )
}
$duration = $csvTask.'Repeat: Until: Duration'
[Carbon.TaskScheduler.Month[]]$months = @()
$modifier = $null
$stopAtEnd = $false
[int]$interval = 0
[TimeSpan]$endTime = [TimeSpan]::Zero
[DayOfWeek[]]$daysOfWeek = @()
[TimeSpan]$delay = [TimeSpan]::Zero
[int]$idleTime = 0
$eventChannelName = $null
$triggers = $xmlTask.GetElementsByTagName('Triggers') | Select-Object -First 1
if( -not $triggers -or $triggers.ChildNodes.Count -eq 0 )
{
$scheduleType = [Carbon.TaskScheduler.ScheduleType]::OnDemand
}
elseif( $triggers.ChildNodes.Count -gt 0 )
{
[Xml.XmlElement]$trigger = $triggers.ChildNodes.Item($scheduleIdx++)
if( $trigger | Get-Member -Name 'EndBoundary' )
{
$endDateTime = [datetime]$trigger.EndBoundary
$endTime = New-TimeSpan -Hours $endDateTime.Hour -Minutes $endDateTime.Minute -Seconds $endDateTime.Second
}
$scheduleType,$modifier,$duration,$stopAtEnd,$delay = ConvertFrom-RepetitionElement $trigger
if( $trigger.Name -eq 'TimeTrigger' )
{
$days = @( )
if( $csvTask.'Schedule Type' -eq 'One Time Only' )
{
$scheduleType = 'Once'
$interval = $modifier
$modifier = $null
}
}
elseif( $trigger.Name -eq 'LogonTrigger' )
{
$scheduleType = 'OnLogon'
$interval = 0
$modifier = $null
}
elseif( $trigger.Name -eq 'BootTrigger' )
{
$scheduleType = 'OnStart'
$interval = 0
$modifier = $null
}
elseif( $trigger.Name -eq 'IdleTrigger' )
{
$scheduleType = 'OnIdle'
$interval = 0
$modifier = $null
$settingsNode = $xmlTask.Settings
if( $settingsNode | Get-Member 'IdleSettings' )
{
$idleSettingsNode = $settingsNode.IdleSettings
if( $idleSettingsNode | Get-Member 'Duration' )
{
$idleExpression = $xmlTask.Settings.IdleSettings.Duration
if( $idleExpression -match '^PT(\d+)M$' )
{
$idleTime = $Matches[1]
}
}
}
}
elseif( $trigger.Name -eq 'EventTrigger' )
{
$scheduleType = 'OnEvent'
$subscription = [xml]$trigger.Subscription
$selectNode = $subscription.QueryList.Query.Select
$modifier = $selectNode.InnerText
$eventChannelName = $selectNode.GetAttribute('Path')
}
elseif( $trigger.Name -eq 'SessionStateChangeTrigger' )
{
$scheduleType = [Carbon.TaskScheduler.ScheduleType]::SessionStateChange
}
elseif( $trigger.Name -eq 'RegistrationTrigger' )
{
$scheduleType = [Carbon.TaskScheduler.ScheduleType]::Registration
}
elseif( $trigger.Name -eq 'CalendarTrigger' )
{
if( $trigger.GetElementsByTagName('ScheduleByDay').Count -eq 1 )
{
$scheduleType = 'Daily'
$modifier = $trigger.ScheduleByDay.DaysInterval
$null,$interval,$null,$null = ConvertFrom-RepetitionElement $trigger
}
elseif( $trigger.GetElementsByTagName('ScheduleByWeek').Count -eq 1 )
{
$scheduleType = 'Weekly'
$interval = $modifier
$modifier = $trigger.ScheduleByWeek.WeeksInterval
$days = @( )
$daysOfWeek = $trigger.ScheduleByWeek.DaysOfWeek.ChildNodes | ForEach-Object { [DayOfWeek]$_.Name }
}
elseif( $trigger.GetElementsByTagName('ScheduleByMonth').Count -eq 1 )
{
$scheduleType = 'Monthly'
$monthsNode = $trigger.ScheduleByMonth.Months
$daysOfMonth = $trigger.ScheduleByMonth.DaysOfMonth.ChildNodes | ForEach-Object { $_.InnerText }
if( $daysOfMonth -eq 'Last' )
{
$interval = $modifier
$modifier = 'LastDay'
$days = @()
}
else
{
$days = $daysOfMonth | ForEach-Object { [int]$_ }
$interval = $modifier
# Monthly tasks.
if( $monthsNode.ChildNodes.Count -eq 12 )
{
$modifier = 1
}
else
{
# Non-monthly tasks.
$modifier = $null
}
}
[Carbon.TaskScheduler.Month[]]$months = $monthsNode.ChildNodes | ForEach-Object { ([Carbon.TaskScheduler.Month]$_.Name) }
}
elseif( $triggers.GetElementsByTagName('ScheduleByMonthDayOfWeek').Count -eq 1 )
{
$scheduleType = 'Monthly'
$interval = $modifier
$scheduleNode = $trigger.ScheduleByMonthDayOfWeek
$daysOfWeek = $scheduleNode.DaysOfWeek.ChildNodes | ForEach-Object { [DayOfWeek]$_.Name }
$months = $scheduleNode.Months.ChildNodes | ForEach-Object { ([Carbon.TaskScheduler.Month]$_.Name) }
switch( $scheduleNode.Weeks.Week )
{
1 { $modifier = 'First' }
2 { $modifier = 'Second' }
3 { $modifier = 'Third' }
4 { $modifier = 'Fourth' }
'Last' { $modifier = 'Last' }
}
}
}
}
function ConvertFrom-SchtasksDate
{
param(
[Parameter(Mandatory=$true)]
[string]
$SchtasksDate,
[Parameter(Mandatory=$true)]
[DateTime]
$DefaultValue
)
Set-StrictMode -Version 'Latest'
[DateTime]$dateTime = $DefaultValue
if( -not [DateTime]::TryParse( $SchtasksDate, [ref] $dateTime ) )
{
return $DefaultValue
}
return New-Object 'DateTime' $dateTime.Year,$dateTime.Month,$dateTime.Day
}
function ConvertFrom-SchtasksTime
{
param(
[Parameter(Mandatory=$true)]
[string]
$SchtasksTime
)
Set-StrictMode -Version 'Latest'
[TimeSpan]$timespan = [TimeSpan]::Zero
[DateTime]$dateTime = New-Object 'DateTime' 2015,11,6
$schtasksTime = '{0} {1}' -f (Get-Date).ToString('d'),$SchtasksTime
if( -not [DateTime]::TryParse( $SchtasksTime, [ref] $dateTime ) )
{
return $timespan
}
return New-Object 'TimeSpan' $dateTime.Hour,$dateTime.Minute,$dateTime.Second
}
$startDate = ConvertFrom-SchtasksDate $csvTask.'Start Date' -DefaultValue ([DateTime]::MinValue)
$startTime = ConvertFrom-SchtasksTime $csvTask.'Start Time'
$endDate = ConvertFrom-SchtasksDate $csvTask.'End Date' -DefaultValue ([DateTime]::MaxValue)
$scheduleCtorArgs = @(
$csvTask.'Last Result',
$csvTask.'Stop Task If Runs X Hours And X Mins',
$scheduleType,
$modifier,
$interval,
$startTime,
$startDate,
$endTime,
$endDate,
$daysOfWeek,
$days,
$months,
$csvTask.'Repeat: Every',
$csvTask.'Repeat: Until: Time',
$duration,
$csvTask.'Repeat: Stop If Still Running',
$stopAtEnd,
$delay,
$idleTime,
$eventChannelName
)
$schedule = New-Object -TypeName 'Carbon.TaskScheduler.ScheduleInfo' -ArgumentList $scheduleCtorArgs
$task.Schedules.Add( $schedule )
}
--$idx;
if( -not $wildcardSearch -or $task.FullName -like $Name )
{
$task
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-ServiceAcl
{
<#
.SYNOPSIS
Gets the discretionary access control list (i.e. DACL) for a service.
.DESCRIPTION
You wanted it, you got it! You probably want to use `Get-ServicePermission` instead. If you want to chagne a service's permissions, use `Grant-ServicePermission` or `Revoke-ServicePermissions`.
.LINK
Get-ServicePermission
.LINK
Grant-ServicePermission
.LINK
Revoke-ServicePermission
.EXAMPLE
Get-ServiceAcl -Name Hyperdrive
Gets the `Hyperdrive` service's DACL.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The service whose DACL to return.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$rawSD = Get-ServiceSecurityDescriptor -Name $Name
$rawDacl = $rawSD.DiscretionaryAcl
New-Object Security.AccessControl.DiscretionaryAcl $false,$false,$rawDacl
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-ServiceConfiguration
{
<#
.SYNOPSIS
Gets a service's full configuration, e.g. username, path, failure actions, etc.
.DESCRIPTION
The .NET `ServiceController` object only returns basic information about a service. This function returns a bunch of the missing configuration in the form of a `Carbon.Service.ServiceInfo` object:
* Account name/user name
* Path
* Description
* Failure actions
You can load a specific service using its name, or pipe in `ServiceController` objects.
In addition to this function, Carbon also adds this information as extended type data properties onto the `ServiceController` class. To see it,
Get-Service | Get-Member
The user running this function must have `QueryConfig`, `QueryStatus`, and `EnumerateDependents` permissions on the service. Use `Grant-ServicePermission` to grant these permissions.
This function is new in Carbon 1.8.
.LINK
Grant-ServicePermission
.EXAMPLE
Get-Service | Get-ServiceConfiguration
Demonstrates how you can pipe in a `ServiceController` object to load the service. This works for services on remote computers as well.
.EXAMPLE
Get-ServiceConfiguration -Name 'w3svc'
Demonstrates how you can get a specific service's configuration.
.EXAMPLE
Get-ServiceConfiguration -Name 'w3svc' -ComputerName 'enterprise'
Demonstrates how to get service configuration for a service on a remote computer.
#>
[CmdletBinding()]
[OutputType([Carbon.Service.ServiceInfo])]
param(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,Position=0)]
[string]
# The name of the service.
$Name,
[Parameter(ValueFromPipelineByPropertyName=$true)]
[Alias('MachineName')]
[string]
# The name of the computer where the service lives.
$ComputerName
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
}
process
{
New-Object 'Carbon.Service.ServiceInfo' $Name,$ComputerName
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-ServiceSecurityDescriptor
{
<#
.SYNOPSIS
Gets the raw security descriptor for a service.
.DESCRIPTION
You probably don't want to mess with the raw security descriptor. Try `Get-ServicePermission` instead. Much more useful.
.OUTPUTS
System.Security.AccessControl.RawSecurityDescriptor.
.LINK
Get-ServicePermission
.LINK
Grant-ServicePermissions
.LINK
Revoke-ServicePermissions
.EXAMPLE
Get-ServiceSecurityDescriptor -Name 'Hyperdrive'
Gets the hyperdrive service's raw security descriptor.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the service whose permissions to return.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$sdBytes = [Carbon.Service.ServiceSecurity]::GetServiceSecurityDescriptor($Name)
New-Object Security.AccessControl.RawSecurityDescriptor $sdBytes,0
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-SslCertificateBinding
{
<#
.SYNOPSIS
Gets the SSL certificate bindings on this computer.
.DESCRIPTION
Windows binds SSL certificates to an IP addresses/port combination. This function gets all the SSL bindings on this computer, or a binding for a specific IP/port, or $null if one doesn't exist. The bindings are returned as `Carbon.Certificates.SslCertificateBinding` objects.
.OUTPUTS
Carbon.Certificates.SslCertificateBinding.
.EXAMPLE
> Get-SslCertificateBinding
Gets all the SSL certificate bindings on the local computer.
.EXAMPLE
> Get-SslCertificateBinding -IPAddress 42.37.80.47 -Port 443
Gets the SSL certificate bound to 42.37.80.47, port 443.
.EXAMPLE
> Get-SslCertificateBinding -Port 443
Gets the default SSL certificate bound to ALL the computer's IP addresses on port 443.
#>
[CmdletBinding()]
[OutputType([Carbon.Certificates.SslCertificateBinding])]
param(
[IPAddress]
# The IP address whose certificate(s) to get. Should be in the form IP:port. Optional.
$IPAddress,
[UInt16]
# The port whose certificate(s) to get. Optional.
$Port
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$binding = $null
$lineNum = 0
netsh http show sslcert |
ForEach-Object {
$lineNum += 1
if( -not ($_.Trim()) -and $binding )
{
$ctorArgs = @(
$binding.IPAddress,
$binding.Port,
$binding['Certificate Hash'],
$binding['Application ID'],
$binding['Certificate Store Name'],
$binding['Verify Client Certificate Revocation'],
$binding['Verify Revocation Using Cached Client Certificate Only'],
$binding['Usage Check'],
$binding['Revocation Freshness Time'],
$binding['URL Retrieval Timeout'],
$binding['Ctl Identifier'],
$binding['Ctl Store Name'],
$binding['DS Mapper Usage'],
$binding['Negotiate Client Certificate']
)
New-Object Carbon.Certificates.SslCertificateBinding $ctorArgs
$binding = $null
}
if( $_ -notmatch '^ (.*)\s+: (.*)$' )
{
return
}
$name = $matches[1].Trim()
$value = $matches[2].Trim()
if( $name -eq 'IP:port' )
{
$binding = @{}
$name = "IPPort"
if( $value -notmatch '^(.*):(\d+)$' )
{
Write-Error ('Invalid IP address/port in netsh output: {0}.' -f $value)
}
else
{
$binding['IPAddress'] = $matches[1]
$binding['Port'] = $matches[2]
}
}
if( $value -eq '(null)' )
{
$value = $null
}
elseif( $value -eq 'Enabled' )
{
$value = $true
}
elseif( $value -eq 'Disabled' )
{
$value = $false
}
$binding[$name] = $value
} |
Where-Object {
if( $IPAddress )
{
$_.IPAddress -eq $IPAddress
}
else
{
return $true
}
} |
Where-Object {
if( $Port )
{
$_.Port -eq $Port
}
else
{
return $true
}
}
}
Set-Alias -Name 'Get-SslCertificateBindings' -Value 'Get-SslCertificateBinding'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-TrustedHost
{
<#
.SYNOPSIS
Returns the current computer's trusted hosts list.
.DESCRIPTION
PowerShell stores its trusted hosts list as a comma-separated list of hostnames in the `WSMan` drive. That's not very useful. This function reads that list, splits it, and returns each item.
.OUTPUTS
System.String.
.EXAMPLE
Get-TrustedHost
If the trusted hosts lists contains `example.com`, `api.example.com`, and `docs.example.com`, returns the following:
example.com
api.example.com
docs.example.com
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$trustedHosts = (Get-Item $TrustedHostsPath -Force).Value
if( $trustedHosts )
{
return $trustedHosts -split ','
}
}
Set-Alias -Name 'Get-TrustedHosts' -Value 'Get-TrustedHost'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-User
{
<#
.SYNOPSIS
Gets *local* users.
.DESCRIPTION
`Get-User` gets all *local* users. Use the `UserName` parameter to get a specific user by its username.
The objects returned by `Get-User` are instances of `System.DirectoryServices.AccountManagement.UserPrincipal`. These objects use external resources, which, if they are disposed of correctly, will cause memory leaks. When you're done using the objects returne by `Get-User`, call `Dispose()` on each one to clean up its external resources.
`Get-User` is new in Carbon 2.0.
.OUTPUTS
System.DirectoryServices.AccountManagement.UserPrincipal.
.LINK
Install-User
.LINK
Test-User
.LINK
Uninstall-User
.EXAMPLE
Get-User
Demonstrates how to get all local users.
.EXAMPLE
Get-User -Username LSkywalker
Demonstrates how to get a specific user.
#>
[CmdletBinding()]
[OutputType([System.DirectoryServices.AccountManagement.UserPrincipal])]
param(
[ValidateLength(1,20)]
[string]
# The username for the user.
$UserName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$ctx = New-Object 'DirectoryServices.AccountManagement.PrincipalContext' ([DirectoryServices.AccountManagement.ContextType]::Machine)
if( $Username )
{
$user = [DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity( $ctx, $Username )
if( -not $user )
{
try
{
Write-Error ('Local user ''{0}'' not found.' -f $Username) -ErrorAction:$ErrorActionPreference
return
}
finally
{
$ctx.Dispose()
}
}
return $user
}
else
{
$query = New-Object 'DirectoryServices.AccountManagement.UserPrincipal' $ctx
$searcher = New-Object 'DirectoryServices.AccountManagement.PrincipalSearcher' $query
try
{
$searcher.FindAll()
}
finally
{
$searcher.Dispose()
$query.Dispose()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This function should only be available if the Windows PowerShell v3.0 Server Manager cmdlets aren't already installed.
if( -not (Get-Command -Name 'Get-WindowsFeature*' | Where-Object { $_.ModuleName -ne 'Carbon' }) )
{
function Get-WindowsFeature
{
<#
.SYNOPSIS
Gets a list of available Windows features, or details on a specific windows feature.
.DESCRIPTION
Different versions of Windows use different names for installing Windows features. Use this function to get the list of functions for your operating system.
With no arguments, will return a list of all Windows features. You can use the `Name` parameter to return a specific feature or a list of features that match a wildcard.
**This function is not available on Windows 8/2012.**
.OUTPUTS
PsObject. A generic PsObject with properties DisplayName, Name, and Installed.
.LINK
Install-WindowsFeature
.LINK
Test-WindowsFeature
.LINK
Uninstall-WindowsFeature
.EXAMPLE
Get-WindowsFeature
Returns a list of all available Windows features.
.EXAMPLE
Get-WindowsFeature -Name MSMQ
Returns the MSMQ feature.
.EXAMPLE
Get-WindowsFeature -Name *msmq*
Returns any Windows feature whose name matches the wildcard `*msmq*`.
#>
[CmdletBinding()]
param(
[Parameter()]
[string]
# The feature name to return. Can be a wildcard.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Write-Warning -Message ('Get-WindowsFeature is obsolete and will be removed in a future major version of Carbon.')
if( -not (Assert-WindowsFeatureFunctionsSupported) )
{
return
}
if( $useOCSetup )
{
Get-WmiObject -Class Win32_OptionalFeature |
Where-Object {
if( $Name )
{
return ($_.Name -like $Name)
}
else
{
return $true
}
} |
ForEach-Object {
$properties = @{
Installed = ($_.InstallState -eq 1);
Name = $_.Name;
DisplayName = $_.Caption;
}
New-Object PsObject -Property $properties
}
}
elseif( $useServerManager )
{
servermanagercmd.exe -query |
Where-Object {
if( $Name )
{
return ($_ -match ('\[{0}\]$' -f [Text.RegularExpressions.Regex]::Escape($Name)))
}
else
{
return $true
}
} |
Where-Object { $_ -match '\[(X| )\] ([^[]+) \[(.+)\]' } |
ForEach-Object {
$properties = @{
Installed = ($matches[1] -eq 'X');
Name = $matches[3]
DisplayName = $matches[2];
}
New-Object PsObject -Property $properties
}
}
else
{
Write-Error $supportNotFoundErrorMessage
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Get-WmiLocalUserAccount
{
<#
.SYNOPSIS
Gets a WMI `Win32_UserAccount` object for a *local* user account.
.DESCRIPTION
Man, there are so many ways to get a user account in Windows. This function uses WMI to get a local user account. It returns a `Win32_UserAccount` object. The username has to be less than 20 characters. We don't remember why anymore, but it's probaly a restriction of WMI. Or Windows. Or both.
You can do this with `Get-WmiObject`, but when you try to get a `Win32_UserAccount`, PowerShell reaches out to your domain and gets all the users it finds, even if you filter by name. This is slow! This function stops WMI from talking to your domain, so it is faster.
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/aa394507(v=vs.85).aspx
.EXAMPLE
Get-WmiLocalUserAccount -Username Administrator
Gets the local Administrator account as a `Win32_UserAccount` WMI object.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[ValidateLength(0,20)]
[string]
# The username of the local user to get.
$Username
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
return Get-WmiObject Win32_UserAccount -Filter "Domain='$($env:ComputerName)' and Name='$Username'"
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Grant-Privilege
{
<#
.SYNOPSIS
Grants an identity priveleges to perform system operations.
.DESCRIPTION
*Privilege names are **case-sensitive**.* Valid privileges are documented on Microsoft's website: [Privilege Constants](http://msdn.microsoft.com/en-us/library/windows/desktop/bb530716.aspx) and [Account Right Constants](http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671.aspx). Here is the most current list, as of August 2014:
* SeAssignPrimaryTokenPrivilege
* SeAuditPrivilege
* SeBackupPrivilege
* SeBatchLogonRight
* SeChangeNotifyPrivilege
* SeCreateGlobalPrivilege
* SeCreatePagefilePrivilege
* SeCreatePermanentPrivilege
* SeCreateSymbolicLinkPrivilege
* SeCreateTokenPrivilege
* SeDebugPrivilege
* SeDenyBatchLogonRight
* SeDenyInteractiveLogonRight
* SeDenyNetworkLogonRight
* SeDenyRemoteInteractiveLogonRight
* SeDenyServiceLogonRight
* SeEnableDelegationPrivilege
* SeImpersonatePrivilege
* SeIncreaseBasePriorityPrivilege
* SeIncreaseQuotaPrivilege
* SeIncreaseWorkingSetPrivilege
* SeInteractiveLogonRight
* SeLoadDriverPrivilege
* SeLockMemoryPrivilege
* SeMachineAccountPrivilege
* SeManageVolumePrivilege
* SeNetworkLogonRight
* SeProfileSingleProcessPrivilege
* SeRelabelPrivilege
* SeRemoteInteractiveLogonRight
* SeRemoteShutdownPrivilege
* SeRestorePrivilege
* SeSecurityPrivilege
* SeServiceLogonRight
* SeShutdownPrivilege
* SeSyncAgentPrivilege
* SeSystemEnvironmentPrivilege
* SeSystemProfilePrivilege
* SeSystemtimePrivilege
* SeTakeOwnershipPrivilege
* SeTcbPrivilege
* SeTimeZonePrivilege
* SeTrustedCredManAccessPrivilege
* SeUndockPrivilege
* SeUnsolicitedInputPrivilege
.LINK
Get-Privilege
.LINK
Revoke-Privilege
.LINK
Test-Privilege
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/bb530716.aspx
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671.aspx
.EXAMPLE
Grant-Privilege -Identity Batcomputer -Privilege SeServiceLogonRight
Grants the Batcomputer account the ability to logon as a service. *Privilege names are **case-sensitive**.*
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The identity to grant a privilege.
$Identity,
[Parameter(Mandatory=$true)]
[string[]]
# The privileges to grant. *Privilege names are **case-sensitive**.*
$Privilege
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$account = Resolve-Identity -Name $Identity
if( -not $account )
{
return
}
try
{
[Carbon.Security.Privilege]::GrantPrivileges( $account.FullName, $Privilege )
}
catch
{
$ex = $_.Exception
do
{
if( $ex -is [ComponentModel.Win32Exception] -and $ex.Message -eq 'No such privilege. Indicates a specified privilege does not exist.' )
{
$msg = 'Failed to grant {0} {1} privilege(s): {2} *Privilege names are **case-sensitive**.*' -f `
$account.FullName,($Privilege -join ','),$ex.Message
Write-Error -Message $msg
return
}
else
{
$ex = $ex.InnerException
}
}
while( $ex )
$ex = $_.Exception
Write-Error -Message ('Failed to grant {0} {1} privilege(s): {2}' -f $account.FullName,($Privilege -join ', '),$ex.Message)
while( $ex.InnerException )
{
$ex = $ex.InnerException
Write-Error -Exception $ex
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Initialize-Lcm
{
<#
.SYNOPSIS
Configures a computer's DSC Local Configuration Manager (LCM).
.DESCRIPTION
The Local Configuration Manager (LCM) is the Windows PowerShell Desired State Configuration (DSC) engine. It runs on all target computers, and it is responsible for calling the configuration resources that are included in a DSC configuration script. It can be configured to receive changes (i.e. `Push` mode) or pull and apply changes its own changes (i.e. `Pull` mode).
## Push Mode
Push mode is simplest. The LCM only applies configurations that are pushed to it via `Start-DscConfiguration`. It is expected that all resources needed by the LCM are installed and available on the computer. To use `Push` mode, use the `Push` switch.
## Pull Mode
In order to get a computer to pulls its configuration automatically, you need to configure its LCM so it knows where and how to find its DSC pull server. The pull server holds all the resources and modules needed by the computer's configuration.
The LCM can pull from two sources: a DSC website (the web download manager) or an SMB files hare (the file download manager). To use the web download manager, specify the URL to the website with the `ServerUrl` parameter. To use the file download manager, specify the path to the resources with the `SourcePath` parameter. This path can be an SMB share path or a local (on the LCM's computer) file system path. No matter where the LCM pulls its configuration from, you're responsible for putting all modules, resources, and .mof files at that location.
The most frequently the LCM will *download* new configuration is every 15 minutes. This is the minimum interval. The refresh interval is set via the `RefreshIntervalMinutes` parameter. The LCM will only *apply* a configuration on one of the refreshes. At most, it will apply configuration every 2nd refresh (i.e. every other refresh). You can control the frequency when configuration is applied via the `ConfigurationFrequency` parameter. For example, if `RefreshIntervalMinutes` is set to `30`, and `ConfigurationFrequency` is set to 4, then configuration will be downloaded every 30 minutes, and applied every two hours (i.e. `30 * 4 = 120` minutes).
The `ConfigurationMode` parameter controls *how* the LCM applies its configuration. It supports three values:
* `ApplyOnly`: Configuration is applied once and isn't applied again until a new configuration is detected. If the computer's configuration drifts, no action is taken.
* `ApplyAndMonitor`: The same as `ApplyOnly`, but if the configuration drifts, it is reported in event logs.
* `ApplyAndAutoCorrect`: The same as `ApplyOnly`, and when the configuratio drifts, the discrepency is reported in event logs, and the LCM attempts to correct the configuration drift.
When credentials are needed on the target computer, the DSC system encrypts those credentials with a public key when generating the configuration. Those credentials are then decrypted on the target computer, using the corresponding private key. A computer can't run its configuration until the private key is installed. Use the `CertFile` and `CertPassword` parameters to specify the path to the certificate containing the private key and the private key's password, respectively. This function will use Carbon's `Install-Certificate` function to upload the certificate to the target computer and install it in the proper Windows certificate store. To generate a public/private key pair, use `New-RsaKeyPair`.
Returns an object representing the computer's updated LCM settings.
See [Windows PowerShell Desired State Configuration Local Configuration Manager](http://technet.microsoft.com/en-us/library/dn249922.aspx) for more information.
`Initialize-Lcm` is new in Carbon 2.0.
.LINK
New-RsaKeyPair
.LINK
Start-DscPullConfiguration
.LINK
Install-Certificate
.LINK
http://technet.microsoft.com/en-us/library/dn249922.aspx
.EXAMPLE
Initialize-Lcm -Push -ComputerName '1.2.3.4'
Demonstrates how to configure an LCM to use push mode.
.EXAMPLE
Initialize-Lcm -ConfigurationID 'fc2ffe50-13cd-4cd2-9942-d25ac66d6c13' -ComputerName '10.1.2.3' -ServerUrl 'https://10.4.5.6/PSDSCPullServer.dsc'
Demonstrates the minimum needed to configure a computer (in this case, `10.1.2.3`) to pull its configuration from a DSC web server.
.EXAMPLE
Initialize-Lcm -ConfigurationID 'fc2ffe50-13cd-4cd2-9942-d25ac66d6c13' -ComputerName '10.1.2.3' -SourcePath '\\10.4.5.6\DSCResources'
Demonstrates the minimum needed to configure a computer (in this case, `10.1.2.3`) to pull its configuration from an SMB file share.
.EXAMPLE
Initialize-Lcm -CertFile 'D:\Projects\Resources\PrivateKey.pfx' -CertPassword $secureStringPassword -ConfigurationID 'fc2ffe50-13cd-4cd2-9942-d25ac66d6c13' -ComputerName '10.1.2.3' -SourcePath '\\10.4.5.6\DSCResources'
Demonstrates how to upload the private key certificate on to the targer computer(s).
.EXAMPLE
Initialize-Lcm -RefreshIntervalMinutes 25 -ConfigurationFrequency 3 -ConfigurationID 'fc2ffe50-13cd-4cd2-9942-d25ac66d6c13' -ComputerName '10.1.2.3' -SourcePath '\\10.4.5.6\DSCResources'
Demonstrates how to use the `RefreshIntervalMinutes` and `ConfigurationFrequency` parameters to control when the LCM downloads new configuration and applies that configuration. In this case, new configuration is downloaded every 25 minutes, and apllied every 75 minutes (`RefreshIntervalMinutes * ConfigurationFrequency`).
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true,ParameterSetName='Push')]
[Switch]
# Configures the LCM to receive its configuration via pushes using `Start-DscConfiguration`.
$Push,
[Parameter(Mandatory=$true,ParameterSetName='PullWebDownloadManager')]
[string]
# Configures the LCM to pull its configuration from a DSC website using the web download manager
$ServerUrl,
[Parameter(ParameterSetName='PullWebDownloadManager')]
[Switch]
# When using the web download manager, allow the `ServerUrl` to use an unsecured, http connection when contacting the DSC web pull server.
$AllowUnsecureConnection,
[Parameter(Mandatory=$true,ParameterSetName='PullFileDownloadManager')]
[string]
# Configures the LCM to pull its configuration from an SMB share or directory. This is the path to the SMB share where resources can be found. Local paths are also allowed, e.g. `C:\DscResources`.
$SourcePath,
[Parameter(Mandatory=$true,ParameterSetName='PullWebDownloadManager')]
[Parameter(Mandatory=$true,ParameterSetName='PullFileDownloadManager')]
[Guid]
# The GUID that identifies what configuration to pull to the computer. The Local Configuration Manager will look for a '$Guid.mof' file to pull.
$ConfigurationID,
[Parameter(Mandatory=$true,ParameterSetName='PullWebDownloadManager')]
[Parameter(Mandatory=$true,ParameterSetName='PullFileDownloadManager')]
[ValidateSet('ApplyOnly','ApplyAndMonitor','ApplyAndAutoCorrect')]
[string]
# Specifies how the Local Configuration Manager applies configuration to the target computer(s). It supports three values: `ApplyOnly`, `ApplyAndMonitor`, or `ApplyAndAutoCorrect`.
$ConfigurationMode,
[Parameter(Mandatory=$true)]
[string[]]
# The computer(s) whose Local Configuration Manager to configure.
$ComputerName,
[PSCredential]
# The credentials to use when connecting to the target computer(s).
$Credential,
[Parameter(ParameterSetName='PullWebDownloadManager')]
[Parameter(ParameterSetName='PullFileDownloadManager')]
[Switch]
# Controls whether new configurations downloaded from the configuration server are allowed to overwrite the old ones on the target computer(s).
$AllowModuleOverwrite,
[Alias('Thumbprint')]
[string]
# The thumbprint of the certificate to use to decrypt secrets. If `CertFile` is given, this parameter is ignored in favor of the certificate in `CertFile`.
$CertificateID = $null,
[string]
# The path to the certificate containing the private key to use when decrypting credentials. The certificate will be uploaded and installed for you.
$CertFile,
[object]
# The password for the certificate specified by `CertFile`. It can be a `string` or a `SecureString`.
$CertPassword,
[Alias('RebootNodeIfNeeded')]
[Switch]
# Reboot the target computer(s) if needed.
$RebootIfNeeded,
[Parameter(ParameterSetName='PullWebDownloadManager')]
[Parameter(ParameterSetName='PullFileDownloadManager')]
[ValidateRange(30,[Int32]::MaxValue)]
[Alias('RefreshFrequencyMinutes')]
[int]
# The interval (in minutes) at which the target computer(s) will contact the pull server to *download* its current configuration. The default (and minimum) interval is 15 minutes.
$RefreshIntervalMinutes = 30,
[Parameter(ParameterSetName='PullWebDownloadManager')]
[Parameter(ParameterSetName='PullFileDownloadManager')]
[ValidateRange(1,([int]([Int32]::MaxValue)))]
[int]
# The frequency (in number of `RefreshIntervalMinutes`) at which the target computer will run/implement its current configuration. The default (and minimum) frequency is 2 refresh intervals. This value is multiplied by the `RefreshIntervalMinutes` parameter to calculate the interval in minutes that the configuration is applied.
$ConfigurationFrequency = 1,
[Parameter(ParameterSetName='PullWebDownloadManager')]
[Parameter(ParameterSetName='PullFileDownloadManager')]
[PSCredential]
# The credentials the Local Configuration Manager should use when contacting the pull server.
$LcmCredential
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $CertPassword -and $CertPassword -isnot [securestring] )
{
Write-Warning -Message ('You passed a plain text password to `Initialize-Lcm`. A future version of Carbon will remove support for plain-text passwords. Please pass a `SecureString` instead.')
$CertPassword = ConvertTo-SecureString -String $CertPassword -AsPlainText -Force
}
$thumbprint = $null
if( $CertificateID )
{
$thumbprint = $CertificateID
}
$privateKey = $null
if( $CertFile )
{
$CertFile = Resolve-FullPath -Path $CertFile
if( -not (Test-Path -Path $CertFile -PathType Leaf) )
{
Write-Error ('Certificate file ''{0}'' not found.' -f $CertFile)
return
}
$privateKey = Get-Certificate -Path $CertFile -Password $CertPassword
if( -not $privateKey )
{
return
}
if( -not $privateKey.HasPrivateKey )
{
Write-Error ('Certificate file ''{0}'' does not have a private key.' -f $CertFile)
return
}
$thumbprint = $privateKey.Thumbprint
}
$credentialParam = @{ }
if( $Credential )
{
$credentialParam.Credential = $Credential
}
$ComputerName = $ComputerName |
Where-Object {
if( Test-Connection -ComputerName $_ -Quiet )
{
return $true
}
Write-Error ('Computer ''{0}'' not found or is unreachable.' -f $_)
return $false
}
if( -not $ComputerName )
{
return
}
# Upload the private key, if one was given.
if( $privateKey )
{
$session = New-PSSession -ComputerName $ComputerName @credentialParam
if( -not $session )
{
return
}
try
{
Install-Certificate -Session $session `
-Path $CertFile `
-Password $CertPassword `
-StoreLocation ([Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine) `
-StoreName ([Security.Cryptography.X509Certificates.StoreName]::My) |
Out-Null
}
finally
{
Remove-PSSession -Session $session -WhatIf:$false
}
}
$sessions = New-CimSession -ComputerName $ComputerName @credentialParam
try
{
$originalWhatIf = $WhatIfPreference
$WhatIfPreference = $false
configuration Lcm
{
Set-StrictMode -Off
$configID = $null
if( $ConfigurationID )
{
$configID = $ConfigurationID.ToString()
}
node $AllNodes.NodeName
{
if( $Node.RefreshMode -eq 'Push' )
{
LocalConfigurationManager
{
CertificateID = $thumbprint;
RebootNodeIfNeeded = $RebootIfNeeded;
RefreshMode = 'Push';
}
}
else
{
if( $Node.RefreshMode -like '*FileDownloadManager' )
{
$downloadManagerName = 'DscFileDownloadManager'
$customData = @{ SourcePath = $SourcePath }
}
else
{
$downloadManagerName = 'WebDownloadManager'
$customData = @{
ServerUrl = $ServerUrl;
AllowUnsecureConnection = $AllowUnsecureConnection.ToString();
}
}
LocalConfigurationManager
{
AllowModuleOverwrite = $AllowModuleOverwrite;
CertificateID = $thumbprint;
ConfigurationID = $configID;
ConfigurationMode = $ConfigurationMode;
ConfigurationModeFrequencyMins = $RefreshIntervalMinutes * $ConfigurationFrequency;
Credential = $LcmCredential;
DownloadManagerCustomData = $customData;
DownloadManagerName = $downloadManagerName;
RebootNodeIfNeeded = $RebootIfNeeded;
RefreshFrequencyMins = $RefreshIntervalMinutes;
RefreshMode = 'Pull'
}
}
}
}
$WhatIfPreference = $originalWhatIf
$tempDir = New-TempDirectory -Prefix 'Carbon+Initialize-Lcm+' -WhatIf:$false
try
{
[object[]]$allNodes = $ComputerName | ForEach-Object { @{ NodeName = $_; PSDscAllowPlainTextPassword = $true; RefreshMode = $PSCmdlet.ParameterSetName } }
$configData = @{
AllNodes = $allNodes
}
$whatIfParam = @{ }
if( (Get-Command -Name 'Lcm').Parameters.ContainsKey('WhatIf') )
{
$whatIfParam['WhatIf'] = $false
}
& Lcm -OutputPath $tempDir @whatIfParam -ConfigurationData $configData | Out-Null
Set-DscLocalConfigurationManager -ComputerName $ComputerName -Path $tempDir @credentialParam
Get-DscLocalConfigurationManager -CimSession $sessions
}
finally
{
Remove-Item -Path $tempDir -Recurse -WhatIf:$false
}
}
finally
{
Remove-CimSession -CimSession $sessions -WhatIf:$false
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-Certificate
{
<#
.SYNOPSIS
Installs a certificate in a given store.
.DESCRIPTION
Uses the .NET certificates API to add a certificate to a store for the machine or current user. The user performing the action must have permission to modify the store or the installation will fail.
To install a certificate on a remote computer, create a remoting session with the `New-PSSession` cmdlet, and pass the session object to this function's `Session` parameter. When installing to a remote computer, the certificate's binary data is converted to a base-64 encoded string and sent to the remote computer, where it is converted back into a certificate. If installing a certificate from a file, the file's bytes are converted to base-64, sent to the remote computer, saved as a temporary file, installed, and the temporary file is removed.
The ability to install a certificate on a remote computer was added in Carbon 2.1.0.
.OUTPUTS
System.Security.Cryptography.X509Certificates.X509Certificate2. An X509Certificate2 object representing the newly installed certificate.
.EXAMPLE
> Install-Certificate -Path C:\Users\me\certificate.cer -StoreLocation LocalMachine -StoreName My -Exportable -Password My5up3r53cur3P@55w0rd
Installs the certificate (which is protected by a password) at C:\Users\me\certificate.cer into the local machine's Personal store. The certificate is marked exportable.
.EXAMPLE
Install-Certificate -Path C:\Users\me\certificate.cer -StoreLocation LocalMachine -StoreName My -ComputerName remote1,remote2
Demonstrates how to install a certificate from a file on the local computer into the local machine's personal store on two remote cmoputers, remote1 and remote2. Use the `Credential` parameter to connect as a specific principal.
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='FromFileInWindowsStore')]
[OutputType([Security.Cryptography.X509Certificates.X509Certificate2])]
param(
[Parameter(Mandatory=$true,Position=0,ParameterSetName='FromFileInWindowsStore')]
[Parameter(Mandatory=$true,Position=0,ParameterSetName='FromFileInCustomStore')]
[string]
# The path to the certificate file.
$Path,
[Parameter(Mandatory=$true,Position=0,ParameterSetName='FromCertificateInWindowsStore')]
[Parameter(Mandatory=$true,Position=0,ParameterSetName='FromCertificateInCustomStore')]
[Security.Cryptography.X509Certificates.X509Certificate2]
# The certificate to install.
$Certificate,
[Parameter(Mandatory=$true)]
[Security.Cryptography.X509Certificates.StoreLocation]
# The location of the certificate's store. To see a list of acceptable values, run:
#
# > [Enum]::GetValues([Security.Cryptography.X509Certificates.StoreLocation])
$StoreLocation,
[Parameter(Mandatory=$true,ParameterSetName='FromFileInWindowsStore')]
[Parameter(Mandatory=$true,ParameterSetName='FromCertificateInWindowsStore')]
[Security.Cryptography.X509Certificates.StoreName]
# The name of the certificate's store. To see a list of acceptable values run:
#
# > [Enum]::GetValues([Security.Cryptography.X509Certificates.StoreName])
$StoreName,
[Parameter(Mandatory=$true,ParameterSetName='FromFileInCustomStore')]
[Parameter(Mandatory=$true,ParameterSetName='FromCertificateInCustomStore')]
[string]
# The name of the non-standard, custom store where the certificate should be installed.
$CustomStoreName,
[Parameter(ParameterSetName='FromFileInWindowsStore')]
[Parameter(ParameterSetName='FromFileInCustomStore')]
[Switch]
# Mark the private key as exportable. Only valid if loading the certificate from a file.
$Exportable,
[Parameter(ParameterSetName='FromFileInWindowsStore')]
[Parameter(ParameterSetName='FromFileInCustomStore')]
# The password for the certificate. Should be a `System.Security.SecureString`.
$Password,
[Management.Automation.Runspaces.PSSession[]]
# Use the `Session` parameter to install a certificate on remote computer(s) using PowerShell remoting. Use `New-PSSession` to create a session.
#
# This parameter was added in Carbon 2.1.0.
$Session
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $Password -and $Password -isnot [securestring] )
{
Write-Warning -Message ('You passed a plain text password to `Install-Certificate`. A future version of Carbon will remove support for plain-text passwords. Please pass a `SecureString` instead.')
$Password = ConvertTo-SecureString -String $Password -AsPlainText -Force
}
if( $PSCmdlet.ParameterSetName -like 'FromFile*' )
{
$Path = Resolve-Path -Path $Path
if( -not $Path )
{
return
}
$fileBytes = [IO.File]::ReadAllBytes($Path)
$encodedCert = [Convert]::ToBase64String( $fileBytes )
$keyFlags = [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet
if( $StoreLocation -eq [Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser )
{
$keyFlags = [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::UserKeySet
}
$keyFlags = $keyFlags -bor [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet
if( $Exportable )
{
$keyFlags = $keyFlags -bor [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
}
$Certificate = Get-Certificate -Path $Path -Password $Password -KeyStorageFlags $keyFlags
$fromFile = $true
}
else
{
$encodedCert = [Convert]::ToBase64String( $Certificate.RawData )
$keyFlags = 0
$fromFile = $false
}
$invokeCommandArgs = @{ }
if( $Session )
{
$invokeCommandArgs['Session'] = $Session
}
Invoke-Command @invokeCommandArgs -ScriptBlock {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The base-64 encoded certificate to install.
$EncodedCertificate,
# The password for the certificate.
[securestring]
$Password,
[Parameter(Mandatory=$true)]
[Security.Cryptography.X509Certificates.StoreLocation]
$StoreLocation,
$StoreName,
[string]
$CustomStoreName,
[Security.Cryptography.X509Certificates.X509KeyStorageFlags]
$KeyStorageFlags,
[bool]
$WhatIf,
[Management.Automation.ActionPreference]
$Verbosity
)
Set-StrictMode -Version 'Latest'
$WhatIfPreference = $WhatIf
$VerbosePreference = $Verbosity
$tempDir = 'Carbon+Install-Certificate+{0}' -f [IO.Path]::GetRandomFileName()
$tempDir = Join-Path -Path $env:TEMP -ChildPath $tempDir
New-Item -Path $tempDir -ItemType 'Directory' -WhatIf:$false | Out-Null
try
{
$certBytes = [Convert]::FromBase64String( $EncodedCertificate )
$certFilePath = Join-Path -Path $tempDir -ChildPath ([IO.Path]::GetRandomFileName())
[IO.File]::WriteAllBytes( $certFilePath, $certBytes )
$cert = New-Object 'Security.Cryptography.X509Certificates.X509Certificate2'
$cert.Import( $certFilePath, $Password, $KeyStorageFlags )
if( $CustomStoreName )
{
$store = New-Object 'Security.Cryptography.X509Certificates.X509Store' $CustomStoreName,$StoreLocation
}
else
{
$store = New-Object 'Security.Cryptography.X509Certificates.X509Store' ([Security.Cryptography.X509Certificates.StoreName]$StoreName),$StoreLocation
}
$store.Open( ([Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) )
$description = $cert.FriendlyName
if( -not $description )
{
$description = $cert.Subject
}
if( $PSCmdlet.ShouldProcess( ('install into {0}''s {1} store' -f $StoreLocation,$StoreName), ('{0} ({1})' -f $description,$cert.Thumbprint) ) )
{
Write-Verbose ('Installing certificate ''{0}'' ({1}) into {2}''s {3} store.' -f $description,$cert.Thumbprint,$StoreLocation,$StoreName)
$store.Add( $cert )
}
$store.Close()
}
finally
{
Remove-Item -Path $tempDir -Recurse -ErrorAction Ignore -WhatIf:$false -Force
}
} -ArgumentList $encodedCert,$Password,$StoreLocation,$StoreName,$CustomStoreName,$keyFlags,$WhatIfPreference,$VerbosePreference
return $Certificate
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-Directory
{
<#
.SYNOPSIS
Creates a directory, if it doesn't exist.
.DESCRIPTION
The `Install-Directory` function creates a directory. If the directory already exists, it does nothing. If any parent directories don't exist, they are created, too.
`Install-Directory` was added in Carbon 2.1.0.
.EXAMPLE
Install-Directory -Path 'C:\Projects\Carbon'
Demonstrates how to use create a directory. In this case, the directories `C:\Projects` and `C:\Projects\Carbon` will be created if they don't exist.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to the directory to create.
$Path
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Path -Path $Path -PathType Container) )
{
New-Item -Path $Path -ItemType 'Directory' | Out-String | Write-Verbose
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-Group
{
<#
.SYNOPSIS
Creates a new local group, or updates the settings for an existing group.
.DESCRIPTION
`Install-Group` creates a local group, or, updates a group that already exists.
YOu can get a `System.DirectoryServices.AccountManagement.GroupPrincipal` object representing the group returned to you by using the `PassThru` switch. This object implements the `IDisposable` interface, which means it uses external resources that don't get garbage collected. When you're done using the object, make sure you call `Dispose()` to free those resources, otherwise you'll leak memory. All over the place.
.EXAMPLE
Install-Group -Name TIEFighters -Description 'Users allowed to be TIE fighter pilots.' -Members EMPIRE\Pilots,EMPIRE\DarthVader
If the TIE fighters group doesn't exist, it is created with the given description and default members. If it already exists, its description is updated and the given members are added to it.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
[OutputType([DirectoryServices.AccountManagement.GroupPrincipal])]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the group.
$Name,
[string]
# A description of the group.
$Description = '',
[Alias('Members')]
[string[]]
# Members of the group.
$Member = @(),
[Switch]
# Return the group as a `System.DirectoryServices.AccountManagement.GroupPrincipal`.
#
# This object uses external resources that don't get cleaned up by .NET's garbage collector. In order to avoid memory leaks, make sure you call its `Dispose()` method when you're done with it.
$PassThru
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$ctx = New-Object 'DirectoryServices.AccountManagement.PrincipalContext' ([DirectoryServices.AccountManagement.ContextType]::Machine)
$group = [DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity( $ctx, $Name )
$operation = 'update'
$save = $false
$new = $false
if( -not $group )
{
$operation = 'create'
$new = $true
$group = New-Object 'DirectoryServices.AccountManagement.GroupPrincipal' $ctx
$group.Name = $Name
$group.Description = $Description
$save = $true
}
else
{
# We only update the description if one or the other has a value. This guards against setting description to $null from empty string and vice-versa.
if( $group.Description -ne $Description -and ($group.Description -or $Description) )
{
Write-Verbose -Message ('[{0}] Description {1} -> {2}' -f $Name,$group.Description,$Description)
$group.Description = $Description
$save = $true
}
}
try
{
if( $save -and $PSCmdlet.ShouldProcess( ('local group {0}' -f $Name), $operation ) )
{
if( $new )
{
Write-Verbose -Message ('[{0}] +' -f $Name)
}
$group.Save()
}
if( $Member -and $PSCmdlet.ShouldProcess( ('local group {0}' -f $Name), 'adding members' ) )
{
Add-GroupMember -Name $Name -Member $Member
}
if( $PassThru )
{
return $group
}
}
finally
{
if( -not $PassThru )
{
$group.Dispose()
$ctx.Dispose()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-IisApplication
{
<#
.SYNOPSIS
Creates a new application under a website.
.DESCRIPTION
Creates a new application at `VirtualPath` under website `SiteName` running the code found on the file system under `PhysicalPath`, i.e. if SiteName is is `example.com`, the application is accessible at `example.com/VirtualPath`. If an application already exists at that path, it is removed first. The application can run under a custom application pool using the optional `AppPoolName` parameter. If no app pool is specified, the application runs under the same app pool as the website it runs under.
Beginning with Carbon 2.0, returns a `Microsoft.Web.Administration.Application` object for the new application if one is created or modified.
Beginning with Carbon 2.0, if no app pool name is given, existing application's are updated to use `DefaultAppPool`.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Install-IisApplication -SiteName Peanuts -VirtualPath CharlieBrown -PhysicalPath C:\Path\To\CharlieBrown -AppPoolName CharlieBrownPool
Creates an application at `Peanuts/CharlieBrown` which runs from `Path/To/CharlieBrown`. The application runs under the `CharlieBrownPool`.
.EXAMPLE
Install-IisApplication -SiteName Peanuts -VirtualPath Snoopy -PhysicalPath C:\Path\To\Snoopy
Create an application at Peanuts/Snoopy, which runs from C:\Path\To\Snoopy. It uses the same application as the Peanuts website.
#>
[CmdletBinding()]
[OutputType([Microsoft.Web.Administration.Application])]
param(
[Parameter(Mandatory=$true)]
[string]
# The site where the application should be created.
$SiteName,
[Parameter(Mandatory=$true)]
[Alias('Name')]
[string]
# The name of the application.
$VirtualPath,
[Parameter(Mandatory=$true)]
[Alias('Path')]
[string]
# The path to the application.
$PhysicalPath,
[string]
# The app pool for the application. Default is `DefaultAppPool`.
$AppPoolName,
[Switch]
# Returns IIS application object. This switch is new in Carbon 2.0.
$PassThru
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$site = Get-IisWebsite -SiteName $SiteName
if( -not $site )
{
Write-Error ('[IIS] Website ''{0}'' not found.' -f $SiteName)
return
}
$iisAppPath = Join-IisVirtualPath $SiteName $VirtualPath
$PhysicalPath = Resolve-FullPath -Path $PhysicalPath
if( -not (Test-Path $PhysicalPath -PathType Container) )
{
Write-Verbose ('IIS://{0}: creating physical path {1}' -f $iisAppPath,$PhysicalPath)
$null = New-Item $PhysicalPath -ItemType Directory
}
$appPoolDesc = ''
if( $AppPoolName )
{
$appPoolDesc = '; appPool: {0}' -f $AppPoolName
}
$apps = $site.GetCollection()
$appPath = "/{0}" -f $VirtualPath
$app = Get-IisApplication -SiteName $SiteName -VirtualPath $VirtualPath
$modified = $false
if( -not $app )
{
Write-Verbose ('IIS://{0}: creating application' -f $iisAppPath)
$app = $apps.CreateElement('application') |
Add-IisServerManagerMember -ServerManager $site.ServerManager -PassThru
$app['path'] = $appPath
$apps.Add( $app ) | Out-Null
$modified = $true
}
if( $app['path'] -ne $appPath )
{
$app['path'] = $appPath
$modified = $true
}
if( $AppPoolName -and $app['applicationPool'] -ne $AppPoolName)
{
$app['applicationPool'] = $AppPoolName
$modified = $true
}
$vdir = $null
if( $app | Get-Member 'VirtualDirectories' )
{
$vdir = $app.VirtualDirectories |
Where-Object { $_.Path -eq '/' }
}
if( -not $vdir )
{
Write-Verbose ('IIS://{0}: creating virtual directory' -f $iisAppPath)
$vdirs = $app.GetCollection()
$vdir = $vdirs.CreateElement('virtualDirectory')
$vdir['path'] = '/'
$vdirs.Add( $vdir ) | Out-Null
$modified = $true
}
if( $vdir['physicalPath'] -ne $PhysicalPath )
{
Write-Verbose ('IIS://{0}: setting physical path {1}' -f $iisAppPath,$PhysicalPath)
$vdir['physicalPath'] = $PhysicalPath
$modified = $true
}
if( $modified )
{
Write-Verbose ('IIS://{0}: committing changes' -f $iisAppPath)
$app.CommitChanges()
}
if( $PassThru )
{
return Get-IisApplication -SiteName $SiteName -VirtualPath $VirtualPath
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-IisAppPool
{
<#
.SYNOPSIS
Creates a new app pool.
.DESCRIPTION
By default, creates a 64-bit app pool running as the `ApplicationPoolIdentity` service account under .NET v4.0 with an integrated pipeline.
You can control which version of .NET is used to run an app pool with the `ManagedRuntimeVersion` parameter: versions `v1.0`, `v1.1`, `v2.0`, and `v4.0` are supported.
To run an application pool using the classic pipeline mode, set the `ClassicPipelineMode` switch.
To run an app pool using the 32-bit version of the .NET framework, set the `Enable32BitApps` switch.
An app pool can run as several built-in service accounts, by passing one of them as the value of the `ServiceAccount` parameter: `NetworkService`, `LocalService`, or `LocalSystem` The default is `ApplicationPoolIdentity`, which causes IIS to create and use a custom local account with the name of the app pool. See [Application Pool Identities](http://learn.iis.net/page.aspx/624/application-pool-identities/) for more information.
To run the app pool as a specific user, pass the credentials with the `Credential` parameter. (In some versions of Carbon, there is no `Credential` parameter, so use the `UserName` and `Password` parameters instead.) The user will be granted the `SeBatchLogonRight` privilege.
If an existing app pool exists with name `Name`, it's settings are modified. The app pool isn't deleted. (You can't delete an app pool if there are any websites using it, that's why.)
By default, this function will create an application pool running the latest version of .NET, with an integrated pipeline, as the NetworkService account.
Beginning with Carbon 2.0, the `PassThru` switch will cause this function to return a `Microsoft.Web.Administration.ApplicationPool` object for the created/updated application pool.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
http://learn.iis.net/page.aspx/624/application-pool-identities/
.LINK
New-Credential
.EXAMPLE
Install-IisAppPool -Name Cyberdyne -ServiceAccount NetworkService
Creates a new Cyberdyne application pool, running as NetworkService, using .NET 4.0 and an integrated pipeline. If the Cyberdyne app pool already exists, it is modified to run as NetworkService, to use .NET 4.0 and to use an integrated pipeline.
.EXAMPLE
Install-IisAppPool -Name Cyberdyne -ServiceAccount NetworkService -Enable32BitApps -ClassicPipelineMode
Creates or sets the Cyberdyne app pool to run as NetworkService, in 32-bit mode (i.e. 32-bit applications are enabled), using the classic IIS request pipeline.
.EXAMPLE
Install-IisAppPool -Name Cyberdyne -Credential $charlieBrownCredential
Creates or sets the Cyberdyne app pool to run as the `PEANUTS\charliebrown` domain account, under .NET 4.0, with an integrated pipeline.
#>
[CmdletBinding(DefaultParameterSetName='AsServiceAccount')]
[OutputType([Microsoft.Web.Administration.ApplicationPool])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams","")]
param(
[Parameter(Mandatory=$true)]
[string]
# The app pool's name.
$Name,
[string]
[ValidateSet('v1.0','v1.1','v2.0','v4.0')]
# The managed .NET runtime version to use. Default is 'v4.0'. Valid values are `v1.0`, `v1.1`, `v2.0`, or `v4.0`.
$ManagedRuntimeVersion = 'v4.0',
[int]
[ValidateScript({$_ -gt 0})]
#Idle Timeout value in minutes. Default is 0.
$IdleTimeout = 0,
[Switch]
# Use the classic pipeline mode, i.e. don't use an integrated pipeline.
$ClassicPipelineMode,
[Switch]
# Enable 32-bit applications.
$Enable32BitApps,
[string]
[ValidateSet('NetworkService','LocalService','LocalSystem')]
# Run the app pool under the given local service account. Valid values are `NetworkService`, `LocalService`, and `LocalSystem`. The default is `ApplicationPoolIdentity`, which causes IIS to create a custom local user account for the app pool's identity. The default is `ApplicationPoolIdentity`.
$ServiceAccount,
[Parameter(ParameterSetName='AsSpecificUser',Mandatory=$true,DontShow=$true)]
[string]
# OBSOLETE. The `UserName` parameter will be removed in a future major version of Carbon. Use the `Credential` parameter instead.
$UserName,
[Parameter(ParameterSetName='AsSpecificUser',Mandatory=$true,DontShow=$true)]
# OBSOLETE. The `Password` parameter will be removed in a future major version of Carbon. Use the `Credential` parameter instead.
$Password,
[Parameter(ParameterSetName='AsSpecificUserWithCredential',Mandatory=$true)]
[pscredential]
# The credential to use to run the app pool.
#
# The `Credential` parameter is new in Carbon 2.0.
$Credential,
[Switch]
# Return an object representing the app pool.
$PassThru
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSCmdlet.ParameterSetName -like 'AsSpecificUser*' )
{
if( $PSCmdlet.ParameterSetName -notlike '*WithCredential' )
{
Write-Warning ('`Install-IisAppPool` function''s `UserName` and `Password` parameters are obsolete and will be removed in a future major version of Carbon. Please use the `Credential` parameter instead.')
$Credential = New-Credential -UserName $UserName -Password $Password
}
}
if( $PSCmdlet.ParameterSetName -eq 'AsSpecificUser' -and -not (Test-Identity -Name $Credential.UserName) )
{
Write-Error ('Identity {0} not found. {0} IIS websites and applications assigned to this app pool won''t run.' -f $Credential.UserName,$Name)
}
if( -not (Test-IisAppPool -Name $Name) )
{
Write-Verbose ('Creating IIS Application Pool {0}' -f $Name)
$mgr = New-Object 'Microsoft.Web.Administration.ServerManager'
$appPool = $mgr.ApplicationPools.Add($Name)
$mgr.CommitChanges()
}
$appPool = Get-IisAppPool -Name $Name
$updated = $false
if( $appPool.ManagedRuntimeVersion -ne $ManagedRuntimeVersion )
{
Write-Verbose ('IIS Application Pool {0}: Setting ManagedRuntimeVersion = {0}' -f $Name,$ManagedRuntimeVersion)
$appPool.ManagedRuntimeVersion = $ManagedRuntimeVersion
$updated = $true
}
$pipelineMode = [Microsoft.Web.Administration.ManagedPipelineMode]::Integrated
if( $ClassicPipelineMode )
{
$pipelineMode = [Microsoft.Web.Administration.ManagedPipelineMode]::Classic
}
if( $appPool.ManagedPipelineMode -ne $pipelineMode )
{
Write-Verbose ('IIS Application Pool {0}: Setting ManagedPipelineMode = {0}' -f $Name,$pipelineMode)
$appPool.ManagedPipelineMode = $pipelineMode
$updated = $true
}
$idleTimeoutTimeSpan = New-TimeSpan -Minutes $IdleTimeout
if( $appPool.ProcessModel.IdleTimeout -ne $idleTimeoutTimeSpan )
{
Write-Verbose ('IIS Application Pool {0}: Setting idle timeout = {0}' -f $Name,$idleTimeoutTimeSpan)
$appPool.ProcessModel.IdleTimeout = $idleTimeoutTimeSpan
$updated = $true
}
if( $appPool.Enable32BitAppOnWin64 -ne ([bool]$Enable32BitApps) )
{
Write-Verbose ('IIS Application Pool {0}: Setting Enable32BitAppOnWin64 = {0}' -f $Name,$Enable32BitApps)
$appPool.Enable32BitAppOnWin64 = $Enable32BitApps
$updated = $true
}
if( $PSCmdlet.ParameterSetName -like 'AsSpecificUser*' )
{
if( $appPool.ProcessModel.UserName -ne $Credential.UserName )
{
Write-Verbose ('IIS Application Pool {0}: Setting username = {0}' -f $Name,$Credential.UserName)
$appPool.ProcessModel.IdentityType = [Microsoft.Web.Administration.ProcessModelIdentityType]::SpecificUser
$appPool.ProcessModel.UserName = $Credential.UserName
$appPool.ProcessModel.Password = $Credential.GetNetworkCredential().Password
# On Windows Server 2008 R2, custom app pool users need this privilege.
Grant-Privilege -Identity $Credential.UserName -Privilege SeBatchLogonRight -Verbose:$VerbosePreference
$updated = $true
}
}
else
{
$identityType = [Microsoft.Web.Administration.ProcessModelIdentityType]::ApplicationPoolIdentity
if( $ServiceAccount )
{
$identityType = $ServiceAccount
}
if( $appPool.ProcessModel.IdentityType -ne $identityType )
{
Write-Verbose ('IIS Application Pool {0}: Setting IdentityType = {0}' -f $Name,$identityType)
$appPool.ProcessModel.IdentityType = $identityType
$updated = $true
}
}
if( $updated )
{
$appPool.CommitChanges()
}
# TODO: Pull this out into its own Start-IisAppPool function. I think.
$appPool = Get-IisAppPool -Name $Name
if($appPool -and $appPool.state -eq [Microsoft.Web.Administration.ObjectState]::Stopped )
{
try
{
$appPool.Start()
}
catch
{
Write-Error ('Failed to start {0} app pool: {1}' -f $Name,$_.Exception.Message)
}
}
if( $PassThru )
{
$appPool
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-IisVirtualDirectory
{
<#
.SYNOPSIS
Installs a virtual directory.
.DESCRIPTION
The `Install-IisVirtualDirectory` function creates a virtual directory under website `SiteName` at `/VirtualPath`, serving files out of `PhysicalPath`. If a virtual directory at `VirtualPath` already exists, it is updated in palce. (Before Carbon 2.0, the virtual directory was deleted before installation.)
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Install-IisVirtualDirectory -SiteName 'Peanuts' -VirtualPath 'DogHouse' -PhysicalPath C:\Peanuts\Doghouse
Creates a /DogHouse virtual directory, which serves files from the C:\Peanuts\Doghouse directory. If the Peanuts website responds to hostname `peanuts.com`, the virtual directory is accessible at `peanuts.com/DogHouse`.
.EXAMPLE
Install-IisVirtualDirectory -SiteName 'Peanuts' -VirtualPath 'Brown/Snoopy/DogHouse' -PhysicalPath C:\Peanuts\DogHouse
Creates a DogHouse virtual directory under the `Peanuts` website at `/Brown/Snoopy/DogHouse` serving files out of the `C:\Peanuts\DogHouse` directory. If the Peanuts website responds to hostname `peanuts.com`, the virtual directory is accessible at `peanuts.com/Brown/Snoopy/DogHouse`.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The site where the virtual directory should be created.
$SiteName,
[Parameter(Mandatory=$true)]
[Alias('Name')]
[string]
# The name of the virtual directory. This can contain multiple directory segments for virtual directories not at the root of the website, e.g. First/Second/VirtualDirectory.
$VirtualPath,
[Parameter(Mandatory=$true)]
[Alias('Path')]
[string]
# The file system path to the virtual directory.
$PhysicalPath,
[Switch]
# Deletes the virttual directory before installation, if it exists. Preserves default beheaviro in Carbon before 2.0.
#
# *Does not* delete custom configuration for the virtual directory, just the virtual directory. If you've customized the location of the virtual directory, those customizations will remain in place.
#
# The `Force` switch is new in Carbon 2.0.
$Force
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$site = Get-IisWebsite -Name $SiteName
[Microsoft.Web.Administration.Application]$rootApp = $site.Applications | Where-Object { $_.Path -eq '/' }
if( -not $rootApp )
{
Write-Error ('Default website application not found.')
return
}
$PhysicalPath = Resolve-FullPath -Path $PhysicalPath
$VirtualPath = $VirtualPath.Trim('/')
$VirtualPath = '/{0}' -f $VirtualPath
$vdir = $rootApp.VirtualDirectories | Where-Object { $_.Path -eq $VirtualPath }
if( $Force -and $vdir )
{
Write-IisVerbose $SiteName -VirtualPath $VirtualPath 'REMOVE' '' ''
$rootApp.VirtualDirectories.Remove($vdir)
$site.CommitChanges()
$vdir = $null
$site = Get-IisWebsite -Name $SiteName
$rootApp = $site.Applications | Where-Object { $_.Path -eq '/' }
}
$modified = $false
if( -not $vdir )
{
[Microsoft.Web.Administration.ConfigurationElementCollection]$vdirs = $rootApp.GetCollection()
$vdir = $vdirs.CreateElement('virtualDirectory')
Write-IisVerbose $SiteName -VirtualPath $VirtualPath 'VirtualPath' '' $VirtualPath
$vdir['path'] = $VirtualPath
[void]$vdirs.Add( $vdir )
$modified = $true
}
if( $vdir['physicalPath'] -ne $PhysicalPath )
{
Write-IisVerbose $SiteName -VirtualPath $VirtualPath 'PhysicalPath' $vdir['physicalPath'] $PhysicalPath
$vdir['physicalPath'] = $PhysicalPath
$modified = $true
}
if( $modified )
{
$site.CommitChanges()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-IisWebsite
{
<#
.SYNOPSIS
Installs a website.
.DESCRIPTION
`Install-IisWebsite` installs an IIS website. Anonymous authentication is enabled, and the anonymous user is set to the website's application pool identity. Before Carbon 2.0, if a website already existed, it was deleted and re-created. Beginning with Carbon 2.0, existing websites are modified in place.
If you don't set the website's app pool, IIS will pick one for you (usually `DefaultAppPool`), and `Install-IisWebsite` will never manage the app pool for you (i.e. if someone changes it manually, this function won't set it back to the default). We recommend always supplying an app pool name, even if it is `DefaultAppPool`.
By default, the site listens on (i.e. is bound to) all IP addresses on port 80 (binding `http/*:80:`). Set custom bindings with the `Bindings` argument. Multiple bindings are allowed. Each binding must be in this format (in BNF):
<PROTOCOL> '/' <IP_ADDRESS> ':' <PORT> ':' [ <HOSTNAME> ]
* `PROTOCOL` is one of `http` or `https`.
* `IP_ADDRESS` is a literal IP address, or `*` for all of the computer's IP addresses. This function does not validate if `IPADDRESS` is actually in use on the computer.
* `PORT` is the port to listen on.
* `HOSTNAME` is the website's hostname, for name-based hosting. If no hostname is being used, leave off the `HOSTNAME` part.
Valid bindings are:
* http/*:80:
* https/10.2.3.4:443:
* http/*:80:example.com
## Troubleshooting
In some situations, when you add a website to an application pool that another website/application is part of, the new website will fail to load in a browser with a 500 error saying `Failed to map the path '/'.`. We've been unable to track down the root cause. The solution is to recycle the app pool, e.g. `(Get-IisAppPool -Name 'AppPoolName').Recycle()`.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
Get-IisWebsite
.LINK
Uninstall-IisWebsite
.EXAMPLE
Install-IisWebsite -Name 'Peanuts' -PhysicalPath C:\Peanuts.com
Creates a website named `Peanuts` serving files out of the `C:\Peanuts.com` directory. The website listens on all the computer's IP addresses on port 80.
.EXAMPLE
Install-IisWebsite -Name 'Peanuts' -PhysicalPath C:\Peanuts.com -Bindings 'http/*:80:peanuts.com:'
Creates a website named `Peanuts` which uses name-based hosting to respond to all requests to any of the machine's IP addresses for the `peanuts.com` domain.
.EXAMPLE
Install-IisWebsite -Name 'Peanuts' -PhysicalPath C:\Peanuts.com -AppPoolName 'PeanutsAppPool'
Creates a website named `Peanuts` that runs under the `PeanutsAppPool` app pool
#>
[CmdletBinding()]
[OutputType([Microsoft.Web.Administration.Site])]
param(
[Parameter(Position=0,Mandatory=$true)]
[string]
# The name of the website.
$Name,
[Parameter(Position=1,Mandatory=$true)]
[Alias('Path')]
[string]
# The physical path (i.e. on the file system) to the website. If it doesn't exist, it will be created for you.
$PhysicalPath,
[Parameter(Position=2)]
[Alias('Bindings')]
[string[]]
# The site's network bindings. Default is `http/*:80:`. Bindings should be specified in protocol/IPAddress:Port:Hostname format.
#
# * Protocol should be http or https.
# * IPAddress can be a literal IP address or `*`, which means all of the computer's IP addresses. This function does not validate if `IPAddress` is actually in use on this computer.
# * Leave hostname blank for non-named websites.
$Binding = @('http/*:80:'),
[string]
# The name of the app pool under which the website runs. The app pool must exist. If not provided, IIS picks one for you. No whammy, no whammy! It is recommended that you create an app pool for each website. That's what the IIS Manager does.
$AppPoolName,
[int]
# The site's IIS ID. IIS picks one for you automatically if you don't supply one. Must be greater than 0.
#
# The `SiteID` switch is new in Carbon 2.0.
$SiteID,
[Switch]
# Return a `Microsoft.Web.Administration.Site` object for the website.
#
# The `PassThru` switch is new in Carbon 2.0.
$PassThru,
[Switch]
# Deletes the website before installation, if it exists. Preserves default beheaviro in Carbon before 2.0.
#
# The `Force` switch is new in Carbon 2.0.
$Force
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$bindingRegex = '^(?<Protocol>https?):?//?(?<IPAddress>\*|[\d\.]+):(?<Port>\d+):?(?<HostName>.*)$'
filter ConvertTo-Binding
{
param(
[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
[string]
$InputObject
)
Set-StrictMode -Version 'Latest'
$InputObject -match $bindingRegex | Out-Null
[pscustomobject]@{
'Protocol' = $Matches['Protocol'];
'IPAddress' = $Matches['IPAddress'];
'Port' = $Matches['Port'];
'HostName' = $Matches['HostName'];
} |
Add-Member -MemberType ScriptProperty -Name 'BindingInformation' -Value { '{0}:{1}:{2}' -f $this.IPAddress,$this.Port,$this.HostName } -PassThru
}
$PhysicalPath = Resolve-FullPath -Path $PhysicalPath
if( -not (Test-Path $PhysicalPath -PathType Container) )
{
New-Item $PhysicalPath -ItemType Directory | Out-String | Write-Verbose
}
$invalidBindings = $Binding |
Where-Object { $_ -notmatch $bindingRegex }
if( $invalidBindings )
{
$invalidBindings = $invalidBindings -join "`n`t"
$errorMsg = "The following bindings are invalid. The correct format is protocol/IPAddress:Port:Hostname. Protocol and IP address must be separted by a single slash, not ://. IP address can be * for all IP addresses. Hostname is optional. If hostname is not provided, the binding must end with a colon.`n`t{0}" -f $invalidBindings
Write-Error $errorMsg
return
}
if( $Force )
{
Uninstall-IisWebsite -Name $Name
}
[Microsoft.Web.Administration.Site]$site = $null
$modified = $false
if( -not (Test-IisWebsite -Name $Name) )
{
Write-Verbose -Message ('Creating website ''{0}'' ({1}).' -f $Name,$PhysicalPath)
$firstBinding = $Binding | Select-Object -First 1 | ConvertTo-Binding
$mgr = New-Object 'Microsoft.Web.Administration.ServerManager'
$site = $mgr.Sites.Add( $Name, $firstBinding.Protocol, $firstBinding.BindingInformation, $PhysicalPath )
$mgr.CommitChanges()
}
$site = Get-IisWebsite -Name $Name
$expectedBindings = New-Object 'Collections.Generic.Hashset[string]'
$Binding | ConvertTo-Binding | ForEach-Object { [void]$expectedBindings.Add( ('{0}/{1}' -f $_.Protocol,$_.BindingInformation) ) }
$bindingsToRemove = $site.Bindings | Where-Object { -not $expectedBindings.Contains( ('{0}/{1}' -f $_.Protocol,$_.BindingInformation ) ) }
foreach( $bindingToRemove in $bindingsToRemove )
{
Write-IisVerbose $Name 'Binding' ('{0}/{1}' -f $bindingToRemove.Protocol,$bindingToRemove.BindingInformation)
$site.Bindings.Remove( $bindingToRemove )
$modified = $true
}
$existingBindings = New-Object 'Collections.Generic.Hashset[string]'
$site.Bindings | ForEach-Object { [void]$existingBindings.Add( ('{0}/{1}' -f $_.Protocol,$_.BindingInformation) ) }
$bindingsToAdd = $Binding | ConvertTo-Binding | Where-Object { -not $existingBindings.Contains( ('{0}/{1}' -f $_.Protocol,$_.BindingInformation ) ) }
foreach( $bindingToAdd in $bindingsToAdd )
{
Write-IisVerbose $Name 'Binding' '' ('{0}/{1}' -f $bindingToAdd.Protocol,$bindingToAdd.BindingInformation)
$site.Bindings.Add( $bindingToAdd.BindingInformation, $bindingToAdd.Protocol ) | Out-Null
$modified = $true
}
[Microsoft.Web.Administration.Application]$rootApp = $null
if( $site.Applications.Count -eq 0 )
{
$rootApp = $site.Applications.Add("/", $PhysicalPath)
$modifed = $true
}
else
{
$rootApp = $site.Applications | Where-Object { $_.Path -eq '/' }
}
if( $site.PhysicalPath -ne $PhysicalPath )
{
Write-IisVerbose $Name 'PhysicalPath' $site.PhysicalPath $PhysicalPath
[Microsoft.Web.Administration.VirtualDirectory]$vdir = $rootApp.VirtualDirectories | Where-Object { $_.Path -eq '/' }
$vdir.PhysicalPath = $PhysicalPath
$modified = $true
}
if( $AppPoolName )
{
if( $rootApp.ApplicationPoolName -ne $AppPoolName )
{
Write-IisVerbose $Name 'AppPool' $rootApp.ApplicationPoolName $AppPoolName
$rootApp.ApplicationPoolName = $AppPoolName
$modified = $true
}
}
if( $modified )
{
$site.CommitChanges()
}
if( $SiteID )
{
Set-IisWebsiteID -SiteName $Name -ID $SiteID
}
# Make sure anonymous authentication is enabled and uses the application pool identity
$security = Get-IisSecurityAuthentication -SiteName $Name -VirtualPath '/' -Anonymous
Write-IisVerbose $Name 'Anonymous Authentication UserName' $security['username'] ''
$security['username'] = ''
$security.CommitChanges()
# Now, wait until site is actually running
$tries = 0
$website = $null
do
{
$website = Get-IisWebsite -SiteName $Name
$tries += 1
if($website.State -ne 'Unknown')
{
break
}
else
{
Start-Sleep -Milliseconds 100
}
}
while( $tries -lt 100 )
if( $PassThru )
{
return $website
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-Junction
{
<#
.SYNOPSIS
Creates a junction, or updates an existing junction if its target is different.
.DESCRIPTION
Creates a junction given by `-Link` which points to the path given by `-Target`. If `Link` exists, deletes it and re-creates it if it doesn't point to `Target`.
Both `-Link` and `-Target` parameters accept relative paths for values. Any non-rooted paths are converted to full paths using the current location, i.e. the path returned by `Get-Location`.
Beginning with Carbon 2.0, returns a `System.IO.DirectoryInfo` object for the target path, if one is created. Returns a `System.IO.DirectoryInfo` object for the junction, if it is created and/or updated.
.OUTPUTS
System.IO.DirectoryInfo. To return a `DirectoryInfo` object for installed junction, use the `PassThru` switch.
.LINK
New-Junction
.LINK
Remove-Junction
.EXAMPLE
Install-Junction -Link 'C:\Windows\system32Link' -Target 'C:\Windows\system32'
Creates the `C:\Windows\system32Link` directory, which points to `C:\Windows\system32`.
.EXAMPLE
Install-Junction -Link C:\Projects\Foobar -Target 'C:\Foo\bar' -Force
This example demonstrates how to create the target directory if it doesn't exist. After this example runs, the directory `C:\Foo\bar` and junction `C:\Projects\Foobar` will be created.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
[OutputType([IO.DirectoryInfo])]
param(
[Parameter(Mandatory=$true)]
[Alias("Junction")]
[string]
# The junction to create/update. Relative paths are converted to absolute paths using the current location.
$Link,
[Parameter(Mandatory=$true)]
[string]
# The target of the junction, i.e. where the junction will point to. Relative paths are converted to absolute paths using the curent location.
$Target,
[Switch]
# Return a `DirectoryInfo` object for the installed junction. Returns nothing if `WhatIf` switch is used. This switch is new in Carbon 2.0.
$PassThru,
[Switch]
# Create the target directory if it does not exist.
$Force
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$Link = Resolve-FullPath -Path $Link
$Target = Resolve-FullPath -Path $Target
if( Test-Path -LiteralPath $Target -PathType Leaf )
{
Write-Error ('Unable to create junction {0}: target {1} exists and is a file.' -f $Link,$Target)
return
}
if( -not (Test-Path -LiteralPath $Target -PathType Container) )
{
if( $Force )
{
New-Item -Path $Target -ItemType Directory -Force | Out-String | Write-Verbose
}
else
{
Write-Error ('Unable to create junction {0}: target {1} not found. Use the `-Force` switch to create target paths that don''t exist.' -f $Link,$Target)
return
}
}
if( Test-Path -LiteralPath $Link -PathType Container )
{
$junction = Get-Item -LiteralPath $Link -Force
if( -not $junction.IsJunction )
{
Write-Error ('Failed to create junction ''{0}'': a directory exists with that path and it is not a junction.' -f $Link)
return
}
if( $junction.TargetPath -eq $Target )
{
return
}
Remove-Junction -LiteralPath $Link
}
if( $PSCmdlet.ShouldProcess( $Target, ("creating '{0}' junction" -f $Link) ) )
{
$result = New-Junction -Link $Link -Target $target -Verbose:$false
if( $PassThru )
{
return $result
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-Msi
{
<#
.SYNOPSIS
Installs software from an MSI file.
.DESCRIPTION
`Install-Msi` installs software from an MSI file. If the install fails, it writes an error. Installation is always done in quiet mode, i.e. you won't see any UI.
In Carbon 1.9 and earlier, this function was called `Invoke-WindowsInstaller`.
Beginning with Carbon 2.0, `Install-Msi` only runs the MSI if the software isn't installed. Use the `-Force` switch to always run the installer.
.EXAMPLE
Install-Msi -Path Path\to\installer.msi
Runs installer.msi, and waits untils for the installer to finish. If the installer has a UI, it is shown to the user.
.EXAMPLE
Get-ChildItem *.msi | Install-Msi
Demonstrates how to pipe MSI files into `Install-Msi` for installation.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[Alias('FullName')]
[string[]]
# The path to the installer to run. Wildcards supported.
$Path,
[Parameter(DontShow=$true)]
[Switch]
# OBSOLETE. Installers are run in quiet mode by default. This switch will be removed in a future major version of Carbon.
$Quiet,
[Switch]
# Install the MSI even if it has already been installed. Will cause a repair/reinstall to run.
$Force
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSBoundParameters.ContainsKey( 'Quiet' ) )
{
Write-Warning ('Install-Msi''s `Quiet` switch is obsolete and will be removed in a future major version of Carbon. Installers are run in quiet mode by default. Please remove usages of the `Quiet` switch.')
}
Get-Msi -Path $Path |
Where-Object {
if( $Force )
{
return $true
}
$installInfo = Get-ProgramInstallInfo -Name $_.ProductName -ErrorAction Ignore
if( -not $installInfo )
{
return $true
}
$result = ($installInfo.ProductCode -ne $_.ProductCode)
if( -not $result )
{
Write-Verbose -Message ('[MSI] [{0}] Installed {1}.' -f $installInfo.DisplayName,$installInfo.InstallDate)
}
return $result
} |
ForEach-Object {
$msi = $_
if( $PSCmdlet.ShouldProcess( $msi.Path, "install" ) )
{
Write-Verbose -Message ('[MSI] [{0}] Installing from {1}.' -f $msi.ProductName,$msi.Path)
$msiProcess = Start-Process -FilePath "msiexec.exe" -ArgumentList "/quiet","/i",('"{0}"' -f $msi.Path) -NoNewWindow -Wait -PassThru
if( $msiProcess.ExitCode -ne $null -and $msiProcess.ExitCode -ne 0 )
{
Write-Error ("{0} {1} installation failed. (Exit code: {2}; MSI: {3})" -f $msi.ProductName,$msi.ProductVersion,$msiProcess.ExitCode,$msi.Path)
}
}
}
}
Set-Alias -Name 'Invoke-WindowsInstaller' -Value 'Install-Msi'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-Msmq
{
<#
.SYNOPSIS
Installs Microsoft's Message Queueing system/feature.
.DESCRIPTION
Microsoft's MSMQ is *not* installed by default. It has to be turned on manually. This function will enable the MSMQ feature. There are two sub-features: Active Directory integration and HTTP support. These can also be enabled by setting the `ActiveDirectoryIntegration` and `HttpSupport` switches, respectively. If MSMQ will be working with queues on other machines, you'll need to enable DTC (the Distributed Transaction Coordinator) by passing the `DTC` switch.
This function uses Microsoft's feature management command line utilities: `ocsetup.exe` or `servermanagercmd.exe`. **A word of warning**, however. In our experience, **these tools do not seem to work as advertised**. They are very slow, and, at least with MSMQ, we have intermittent errors installing it on our developer's Windows 7 computers. We strongly recommend you install MSMQ manually on a base VM or computer image so that it's a standard part of your installation. If that isn't possible in your environment, good luck! let us know how it goes.
If you know better ways of installing MSMQ or other Windows features, or can help us figure out why Microsoft's command line installation tools don't work consistently, we would appreciate it.
.EXAMPLE
Install-Msmq
Installs MSMQ on this meachine. In our experience, this may or may not work. You'll want to check that the MSMQ service exists and is running after this. Please help us make this better!
.EXAMPLE
Install-Msmq -HttpSupport -ActiveDirectoryIntegration -Dtc
Installs MSMQ with the HTTP support and Active Directory sub-features. Enables and starts the Distributed Transaction Coordinator.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Switch]
# Enable HTTP Support
$HttpSupport,
[Switch]
# Enable Active Directory Integrations
$ActiveDirectoryIntegration,
[Switch]
# Will MSMQ be participating in external, distributed transactions? I.e. will it be sending messages to queues on other machines?
$Dtc
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Write-Warning -Message ('Install-Msmq is obsolete and will be removed in a future major version of Carbon.')
$optionalArgs = @{ }
if( $HttpSupport )
{
$optionalArgs.MsmqHttpSupport = $true
}
if( $ActiveDirectoryIntegration )
{
$optionalArgs.MsmqActiveDirectoryIntegration = $true
}
Install-WindowsFeature -Msmq @optionalArgs
if( $Dtc )
{
Set-Service -Name MSDTC -StartupType Automatic
Start-Service -Name MSDTC
$svc = Get-Service -Name MSDTC
$svc.WaitForStatus( [ServiceProcess.ServiceControllerStatus]::Running )
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-PerformanceCounter
{
<#
.SYNOPSIS
Installs a performance counter.
.DESCRIPTION
Creates a new performance counter with a specific name, description, and type under a given category. The counter's category is re-created: its current counters are retrieved, the category is removed, a the category is re-created. Unfortunately, we haven't been able to find any .NET APIs that allow us to delete and create an existing counter.
If you're creating a performance counter that relies on an accompanying base counter, use the `BaseName`, `BaseDescription`, and `BaseType` parameters to properly add the base counter.
.LINK
http://msdn.microsoft.com/en-us/library/system.diagnostics.performancecountertype.aspx
.EXAMPLE
Install-PerformanceCounter -CategoryName ToyotaCamry -Name MilesPerGallon -Description 'The miles per gallon fuel efficiency.' -Type NumberOfItems32
Creates a new miles per gallon performance counter for the ToyotaCamry category.
.EXAMPLE
Install-PerformanceCounter -CategoryName "Dispatcher" -Name "Average Dispatch time" -Type AverageTimer32 -BaseName "Average Dispatch Base" -BaseType AverageBase -Force
Creates a counter to collect average timings, with a base counter. Some counters require base counters, which have to be added a specific way to work properly.
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='SimpleCounter')]
param(
[Parameter(Mandatory=$true)]
[string]
# The category's name where the counter will be created.
$CategoryName,
[Parameter(Mandatory=$true)]
[string]
# The performance counter's name.
$Name,
[string]
# The performance counter's description (i.e. help message).
$Description,
[Parameter(Mandatory=$true)]
[Diagnostics.PerformanceCounterType]
# The performance counter's type (from the Diagnostics.PerformanceCounterType enumeration).
$Type,
[Parameter(Mandatory=$true,ParameterSetName='WithBaseCounter')]
[string]
# The base performance counter's name.
$BaseName,
[Parameter(ParameterSetName='WithBaseCounter')]
[string]
# The base performance counter's description (i.e. help message).
$BaseDescription,
[Parameter(Mandatory=$true,ParameterSetName='WithBaseCounter')]
[Diagnostics.PerformanceCounterType]
# The base performance counter's type (from the Diagnostics.PerformanceCounterType enumeration).
$BaseType,
[Switch]
# Re-create the performance counter even if it already exists.
$Force
)
Set-StrictMode -Version Latest
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$currentCounters = @( Get-PerformanceCounter -CategoryName $CategoryName )
$counter = $currentCounters |
Where-Object {
$_.CounterName -eq $Name -and `
$_.CounterHelp -eq $Description -and `
$_.CounterType -eq $Type
}
if( $counter -and -not $Force)
{
return
}
if( $PSCmdlet.ParameterSetName -eq 'WithBaseCounter' )
{
$baseCounter = $currentCounters |
Where-Object {
$_.CounterName -eq $BaseName -and `
$_.CounterHelp -eq $BaseDescription -and `
$_.CounterType -eq $BaseType
}
if( $baseCounter -and -not $Force)
{
return
}
}
else
{
$BaseName = $null
}
$counters = New-Object Diagnostics.CounterCreationDataCollection
$currentCounters |
Where-Object { $_.CounterName -ne $Name -and $_.CounterName -ne $BaseName } |
ForEach-Object {
$creationData = New-Object Diagnostics.CounterCreationData $_.CounterName,$_.CounterHelp,$_.CounterType
[void] $counters.Add( $creationData )
}
$newCounterData = New-Object Diagnostics.CounterCreationData $Name,$Description,$Type
[void] $counters.Add( $newCounterData )
$baseMsg = ''
if( $PSCmdlet.ParameterSetName -eq 'WithBaseCounter' )
{
$newBaseCounterData = New-Object Diagnostics.CounterCreationData $BaseName,$BaseDescription,$BaseType
[void] $counters.Add( $newBaseCounterData )
$baseMsg = ' with base counter ''{0}'' ({1})' -f $BaseName,$BaseType
}
$msg = "Installing '{0}' performance counter '{1}' ({2}){3}." -f $CategoryName,$Name,$Type,$baseMsg
if( $pscmdlet.ShouldProcess( $CategoryName, "install performance counter '$Name'" ) )
{
Uninstall-PerformanceCounterCategory -CategoryName $CategoryName
[void] [Diagnostics.PerformanceCounterCategory]::Create( $CategoryName, '', $counters )
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-RegistryKey
{
<#
.SYNOPSIS
Creates a registry key. If it already exists, does nothing.
.DESCRIPTION
Given the path to a registry key, creates the key and all its parents. If the key already exists, nothing happens.
.EXAMPLE
Install-RegistryKey -Path 'hklm:\Software\Carbon\Test'
Creates the `hklm:\Software\Carbon\Temp` registry key if it doesn't already exist.
#>
[CmdletBinding(SupportsShouldPRocess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to the registry key to create.
$Path
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Path -Path $Path -PathType Container) )
{
New-Item -Path $Path -ItemType RegistryKey -Force | Out-String | Write-Verbose
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-ScheduledTask
{
<#
.SYNOPSIS
Installs a scheduled task on the current computer.
.DESCRIPTION
The `Install-ScheduledTask` function uses `schtasks.exe` to install a scheduled task on the current computer. If a task with the same name already exists, the existing task is left in place. Use the `-Force` switch to force `Install-ScheduledTask` to delete any existing tasks before installation.
If a new task is created, a `Carbon.TaskScheduler.TaskInfo` object is returned.
The `schtasks.exe` command line application is pretty limited in the kind of tasks it will create. If you need a scheduled task created with options not supported by `Install-ScheduledTask`, you can create an XML file using the [Task Scheduler Schema](http://msdn.microsoft.com/en-us/library/windows/desktop/aa383609.aspx) or create a task with the Task Scheduler MMC then export that task as XML with the `schtasks.exe /query /xml /tn <TaskName>`. Pass the XML file (or the raw XML) with the `TaskXmlFilePath` or `TaskXml` parameters, respectively.
.LINK
Get-ScheduledTask
.LINK
Test-ScheduledTask
.LINK
Uninstall-ScheduledTask
.LINK
http://technet.microsoft.com/en-us/library/cc725744.aspx#BKMK_create
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/aa383609.aspx
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'C:\Windows\system32\notepad.exe' -Minute 5
Creates a scheduled task "CarbonSample" to run notepad.exe every five minutes. No credential or principal is provided, so the task will run as `System`.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'C:\Windows\system32\notepad.exe' -Minute 1 -TaskCredential (Get-Credential 'runasuser')
Demonstrates how to run a task every minute as a specific user with the `TaskCredential` parameter.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'C:\Windows\system32\notepad.exe' -Minute 1 -Principal LocalService
Demonstrates how to run a task every minute as a built-in principal, in this case `Local Service`.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'calc.exe' -Minute 5 -StartTime '12:00' -EndTime '14:00' -StartDate '6/6/2006' -EndDate '6/6/2006'
Demonstrates how to run a task every 5 minutes between the given start date/time and end date/time. In this case, the task will run between noon and 2 pm on `6/6/2006`.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad' -Hourly 1
Creates a scheduled task `CarbonSample` which runs `notepad.exe` every hour as the `LocalService` user.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -Weekly 1
Demonstrates how to run a task ever *N* weeks, in this case every week.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -Monthly
Demonstrates how to run a task the 1st of every month.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -Monthly -DayOfMonth 15
Demonstrates how to run a monthly task on a specific day of the month.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -Month 1,4,7,10 -DayOfMonth 5
Demonstrates how to run a task on specific months of the year on a specific day of the month.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -WeekOfMonth First -DayOfWeek Sunday
Demonstrates how to run a task on a specific week of each month. In this case, the task will run the first Sunday of every month.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -Month 1,5,9 -WeekOfMonth First -DayOfWeek Sunday
Demonstrates how to run a task on a specific week of specific months. In this case, the task will run the first Sunday of January, May, and September.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -LastDayOfMonth
Demonstrates how to run a task the last day of every month.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -LastDayOfMonth -Month 1,6
Demonstrates how to run a task the last day of specific months. In this case, the task will run the last day of January and June.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -Once -StartTime '0:00'
Demonstrates how to run a task once. In this case, the task will run at midnight of today (which means it probably won't run since it is always past midnight).
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -OnStart
Demonstrates how to run a task when the computer starts up.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -OnStart -Delay '0:30'
Demonstrates how to run a task when the computer starts up after a certain amount of time passes. In this case, the task will run 30 minutes after the computer starts.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -OnLogon -TaskCredential (Get-Credential 'runasuser')
Demonstrates how to run a task when the user running the task logs on. Usually you want to pass a credential when setting up a logon task, since the built-in users never log in.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -OnLogon -Delay '1:45' -TaskCredential (Get-Credential 'runasuser')
Demonstrates how to run a task after a certain amount of time passes after a user logs in. In this case, the task will run after 1 hour and 45 minutes after `runasuser` logs in.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -OnIdle
Demonstrates how to run a task when the computer is idle.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -OnIdle -Delay '0:05'
Demonstrates how to run a task when the computer has been idle for a desired amount of time. In this case, the task will run after the computer has been idle for 5 minutes.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'wevtvwr.msc' -OnEvent -EventChannelName System -EventXPathQuery '*[Sytem/EventID=101]'
Demonstrates how to run an event when certain events are written to the event log. In this case, wevtvwr.msc will run whenever an event with ID `101` is published in the System event channel.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -TaskXmlFilePath $taskXmlPath
Demonstrates how to create a task using the [Task Scheduler XML schema](http://msdn.microsoft.com/en-us/library/windows/desktop/aa383609.aspx) for a task that runs as a built-in principal. You can export task XML with the `schtasks /query /xml /tn <Name>` command.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -TaskXmlFilePath $taskXmlPath -TaskCredential (Get-Credential 'runasuser')
Demonstrates how to create a task using the [Task Scheduler XML schema](http://msdn.microsoft.com/en-us/library/windows/desktop/aa383609.aspx) for a task that will run as a specific user. The username in the XML file should match the username in the credential.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -TaskXml $taskXml
Demonstrates how to create a task using raw XML that conforms to the [Task Scheduler XML schema](http://msdn.microsoft.com/en-us/library/windows/desktop/aa383609.aspx) for a task that will run as a built-in principal. In this case, `$taskXml` should be an XML document.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonSample' -TaskToRun 'notepad.exe' -TaskXml $taskXml -TaskCredential (Get-Credential 'runasuser')
Demonstrates how to create a task using raw XML that conforms to the [Task Scheduler XML schema](http://msdn.microsoft.com/en-us/library/windows/desktop/aa383609.aspx) for a task that will run as a specific user. In this case, `$taskXml` should be an XML document. The username in the XML document should match the username in the credential.
.EXAMPLE
Install-ScheduledTask -Name 'CarbonTasks\CarbonSample' -TaskToRun 'notepad.exe' -Monthly
Demonstrates how to create tasks under a folder/directory: use a path for the `Name` parameter.
#>
[CmdletBinding()]
[OutputType([Carbon.TaskScheduler.TaskInfo])]
param(
[Parameter(Mandatory=$true)]
[ValidateLength(1,238)]
[Alias('TaskName')]
[string]
# The name of the scheduled task to create. Paths are allowed to create tasks under folders.
$Name,
[Parameter(Mandatory=$true,ParameterSetName='Minute')]
[Parameter(Mandatory=$true,ParameterSetName='Hourly')]
[Parameter(Mandatory=$true,ParameterSetName='Daily')]
[Parameter(Mandatory=$true,ParameterSetName='Weekly')]
[Parameter(Mandatory=$true,ParameterSetName='Monthly')]
[Parameter(Mandatory=$true,ParameterSetName='Month')]
[Parameter(Mandatory=$true,ParameterSetName='LastDayOfMonth')]
[Parameter(Mandatory=$true,ParameterSetName='WeekOfMonth')]
[Parameter(Mandatory=$true,ParameterSetName='Once')]
[Parameter(Mandatory=$true,ParameterSetName='OnStart')]
[Parameter(Mandatory=$true,ParameterSetName='OnLogon')]
[Parameter(Mandatory=$true,ParameterSetName='OnIdle')]
[Parameter(Mandatory=$true,ParameterSetName='OnEvent')]
[ValidateLength(1,262)]
[string]
# The task/program to execute, including arguments/parameters.
$TaskToRun,
[Parameter(ParameterSetName='Minute',Mandatory=$true)]
[ValidateRange(1,1439)]
[int]
# Create a scheduled task that runs every N minutes.
$Minute,
[Parameter(ParameterSetName='Hourly',Mandatory=$true)]
[ValidateRange(1,23)]
[int]
# Create a scheduled task that runs every N hours.
$Hourly,
[Parameter(ParameterSetName='Minute')]
[Parameter(ParameterSetName='Hourly')]
[Switch]
# Stops the task at the `EndTime` or `Duration` if it is still running.
$StopAtEnd,
[Parameter(ParameterSetName='Daily',Mandatory=$true)]
[ValidateRange(1,365)]
[int]
# Creates a scheduled task that runs every N days.
$Daily,
[Parameter(ParameterSetName='Weekly',Mandatory=$true)]
[ValidateRange(1,52)]
[int]
# Creates a scheduled task that runs every N weeks.
$Weekly,
[Parameter(ParameterSetName='Monthly',Mandatory=$true)]
[Switch]
# Create a scheduled task that runs every month.
$Monthly,
[Parameter(ParameterSetName='LastDayOfMonth',Mandatory=$true)]
[Switch]
# Create a scheduled task that runs on the last day of every month. To run on specific months, specify the `Month` parameter.
$LastDayOfMonth,
[Parameter(ParameterSetName='Month',Mandatory=$true)]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[Carbon.TaskScheduler.Month[]]
# Create a scheduled task that runs on specific months. To create a monthly task, use the `Monthly` switch.
$Month,
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month',Mandatory=$true)]
[ValidateRange(1,31)]
[int]
# The day of the month to run a monthly task.
$DayOfMonth,
[Parameter(ParameterSetName='WeekOfMonth',Mandatory=$true)]
[Carbon.TaskScheduler.WeekOfMonth]
# Create a scheduled task that runs a particular week of the month.
$WeekOfMonth,
[Parameter(ParameterSetName='WeekOfMonth',Mandatory=$true)]
[Parameter(ParameterSetName='Weekly')]
[DayOfWeek[]]
# The day of the week to run the task. Default is today.
$DayOfWeek,
[Parameter(ParameterSetName='Once',Mandatory=$true)]
[Switch]
# Create a scheduled task that runs once.
$Once,
[Parameter(ParameterSetName='OnStart',Mandatory=$true)]
[Switch]
# Create a scheduled task that runs at startup.
$OnStart,
[Parameter(ParameterSetName='OnLogon',Mandatory=$true)]
[Switch]
# Create a scheduled task that runs when the user running the task logs on. Requires the `TaskCredential` parameter.
$OnLogon,
[Parameter(ParameterSetName='OnIdle',Mandatory=$true)]
[ValidateRange(1,999)]
[int]
# Create a scheduled task that runs when the computer is idle for N minutes.
$OnIdle,
[Parameter(ParameterSetName='OnEvent',Mandatory=$true)]
[Switch]
# Create a scheduled task that runs when events appear in the Windows event log.
$OnEvent,
[Parameter(ParameterSetName='OnEvent',Mandatory=$true)]
[string]
# The name of the event channel to look at.
$EventChannelName,
[Parameter(ParameterSetName='OnEvent',Mandatory=$true)]
[string]
# The XPath event query to use to determine when to fire `OnEvent` tasks.
$EventXPathQuery,
[Parameter(Mandatory=$true,ParameterSetName='XmlFile')]
[string]
# Install the task from this XML path.
$TaskXmlFilePath,
[Parameter(Mandatory=$true,ParameterSetName='Xml')]
[xml]
# Install the task from this XML.
$TaskXml,
[Parameter(ParameterSetName='Daily')]
[Parameter(ParameterSetName='Weekly')]
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month')]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[ValidateRange(1,599940)]
[int]
# Re-run the task every N minutes.
$Interval,
[Parameter(ParameterSetName='Minute')]
[Parameter(ParameterSetName='Hourly')]
[Parameter(ParameterSetName='Daily')]
[Parameter(ParameterSetName='Weekly')]
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month')]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[Parameter(ParameterSetName='Once')]
[DateTime]
# The date the task can start running.
$StartDate,
[Parameter(ParameterSetName='Minute')]
[Parameter(ParameterSetName='Hourly')]
[Parameter(ParameterSetName='Daily')]
[Parameter(ParameterSetName='Weekly')]
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month')]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[Parameter(ParameterSetName='Once',Mandatory=$true)]
[ValidateScript({ $_ -lt [timespan]'1' })]
[TimeSpan]
# The start time to run the task. Must be less than `24:00`.
$StartTime,
[Parameter(ParameterSetName='Minute')]
[Parameter(ParameterSetName='Hourly')]
[Parameter(ParameterSetName='Daily')]
[Parameter(ParameterSetName='Weekly')]
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month')]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[TimeSpan]
# The duration to run the task. Usually used with `Interval` to repeatedly run a task over a given time span. By default, re-runs for an hour. Can't be used with `EndTime`.
$Duration,
[Parameter(ParameterSetName='Minute')]
[Parameter(ParameterSetName='Hourly')]
[Parameter(ParameterSetName='Daily')]
[Parameter(ParameterSetName='Weekly')]
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month')]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[DateTime]
# The last date the task should run.
$EndDate,
[Parameter(ParameterSetName='Minute')]
[Parameter(ParameterSetName='Hourly')]
[Parameter(ParameterSetName='Daily')]
[Parameter(ParameterSetName='Weekly')]
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month')]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[ValidateScript({ $_ -lt [timespan]'1' })]
[TimeSpan]
# The end time to run the task. Must be less than `24:00`. Can't be used with `Duration`.
$EndTime,
[Parameter(ParameterSetName='Minute')]
[Parameter(ParameterSetName='Hourly')]
[Parameter(ParameterSetName='Daily')]
[Parameter(ParameterSetName='Weekly')]
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month')]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[Parameter(ParameterSetName='Once')]
[Parameter(ParameterSetName='OnStart')]
[Parameter(ParameterSetName='OnLogon')]
[Parameter(ParameterSetName='OnIdle')]
[Parameter(ParameterSetName='OnEvent')]
[Switch]
# Enables the task to run interactively only if the user is currently logged on at the time the job runs. The task will only run if the user is logged on. Must be used with `TaskCredential` parameter.
$Interactive,
[Parameter(ParameterSetName='Minute')]
[Parameter(ParameterSetName='Hourly')]
[Parameter(ParameterSetName='Daily')]
[Parameter(ParameterSetName='Weekly')]
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month')]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[Parameter(ParameterSetName='Once')]
[Parameter(ParameterSetName='OnStart')]
[Parameter(ParameterSetName='OnLogon')]
[Parameter(ParameterSetName='OnIdle')]
[Parameter(ParameterSetName='OnEvent')]
[Switch]
# No password is stored. The task runs non-interactively as the given user, who must be logged in. Only local resources are available. Must be used with `TaskCredential` parameter.
$NoPassword,
[Parameter(ParameterSetName='Minute')]
[Parameter(ParameterSetName='Hourly')]
[Parameter(ParameterSetName='Daily')]
[Parameter(ParameterSetName='Weekly')]
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month')]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[Parameter(ParameterSetName='Once')]
[Parameter(ParameterSetName='OnStart')]
[Parameter(ParameterSetName='OnLogon')]
[Parameter(ParameterSetName='OnIdle')]
[Parameter(ParameterSetName='OnEvent')]
[Switch]
# Marks the task for deletion after its final run.
$HighestAvailableRunLevel,
[Parameter(ParameterSetName='OnStart')]
[Parameter(ParameterSetName='OnLogon')]
[Parameter(ParameterSetName='OnEvent')]
[ValidateScript({ $_ -lt '6.22:40:00'})]
[timespan]
# The wait time to delay the running of the task after the trigger is fired. Must be less than 10,000 minutes (6 days, 22 hours, and 40 minutes).
$Delay,
[Management.Automation.PSCredential]
# The principal the task should run as. Use `Principal` parameter to run as a built-in security principal. Required if `Interactive` or `NoPassword` switches are used.
$TaskCredential,
[Parameter(ParameterSetName='Minute')]
[Parameter(ParameterSetName='Hourly')]
[Parameter(ParameterSetName='Daily')]
[Parameter(ParameterSetName='Weekly')]
[Parameter(ParameterSetName='Monthly')]
[Parameter(ParameterSetName='Month')]
[Parameter(ParameterSetName='LastDayOfMonth')]
[Parameter(ParameterSetName='WeekOfMonth')]
[Parameter(ParameterSetName='Once')]
[Parameter(ParameterSetName='OnStart')]
[Parameter(ParameterSetName='OnLogon')]
[Parameter(ParameterSetName='OnIdle')]
[Parameter(ParameterSetName='OnEvent')]
[ValidateSet('System','LocalService','NetworkService')]
[string]
# The built-in identity to use. The default is `System`. Use the `TaskCredential` parameter to run as non-built-in security principal.
$Principal = 'System',
[Switch]
# Create the task even if a task with the same name already exists (i.e. delete any task with the same name before installation).
$Force
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( (Test-ScheduledTask -Name $Name) )
{
if( $Force )
{
Uninstall-ScheduledTask -Name $Name
}
else
{
Write-Verbose ('Scheduled task ''{0}'' already exists. Use -Force switch to re-create it.' -f $Name)
return
}
}
$parameters = New-Object 'Collections.ArrayList'
if( $TaskCredential )
{
[void]$parameters.Add( '/RU' )
[void]$parameters.Add( $TaskCredential.UserName )
[void]$parameters.Add( '/RP' )
[void]$parameters.Add( $TaskCredential.GetNetworkCredential().Password )
Grant-Privilege -Identity $TaskCredential.UserName -Privilege 'SeBatchLogonRight'
}
elseif( $PSCmdlet.ParameterSetName -notlike 'Xml*' )
{
[void]$parameters.Add( '/RU' )
[void]$parameters.Add( (Resolve-IdentityName -Name $Principal) )
}
function ConvertTo-SchtasksCalendarNameList
{
param(
[Parameter(Mandatory=$true)]
[object[]]
$InputObject
)
Set-StrictMode -Version 'Latest'
$list = $InputObject | ForEach-Object { $_.ToString().Substring(0,3).ToUpperInvariant() }
return $list -join ','
}
$scheduleType = $PSCmdlet.ParameterSetName.ToUpperInvariant()
$modifier = $null
switch -Wildcard ( $PSCmdlet.ParameterSetName )
{
'Minute'
{
$modifier = $Minute
}
'Hourly'
{
$modifier = $Hourly
}
'Daily'
{
$modifier = $Daily
}
'Weekly'
{
$modifier = $Weekly
if( $PSBoundParameters.ContainsKey('DayOfWeek') )
{
[void]$parameters.Add( '/D' )
[void]$parameters.Add( (ConvertTo-SchtasksCalendarNameList $DayOfWeek) )
}
}
'Monthly'
{
$modifier = 1
if( $DayOfMonth )
{
[void]$parameters.Add( '/D' )
[void]$parameters.Add( ($DayOfMonth -join ',') )
}
}
'Month'
{
$scheduleType = 'MONTHLY'
[void]$parameters.Add( '/M' )
[void]$parameters.Add( (ConvertTo-SchtasksCalendarNameList $Month) )
if( ($Month | Select-Object -Unique | Measure-Object).Count -eq 12 )
{
Write-Error ('It looks like you''re trying to schedule a monthly task, since you passed all 12 months as the `Month` parameter. Please use the `-Monthly` switch to schedule a monthly task.')
return
}
if( $DayOfMonth )
{
[void]$parameters.Add( '/D' )
[void]$parameters.Add( ($DayOfMonth -join ',') )
}
}
'LastDayOfMonth'
{
$modifier = 'LASTDAY'
$scheduleType = 'MONTHLY'
[void]$parameters.Add( '/M' )
if( $Month )
{
[void]$parameters.Add( (ConvertTo-SchtasksCalendarNameList $Month) )
}
else
{
[void]$parameters.Add( '*' )
}
}
'WeekOfMonth'
{
$scheduleType = 'MONTHLY'
$modifier = $WeekOfMonth
[void]$parameters.Add( '/D' )
if( $DayOfWeek )
{
if( $DayOfWeek.Count -eq 1 )
{
[void]$parameters.Add( (ConvertTo-SchtasksCalendarNameList $DayOfWeek) )
}
else
{
Write-Error ('Tasks that run during a specific week of the month can only occur on a single weekday (received {0} days: {1}). Please pass one weekday with the `-DayOfWeek` parameter.' -f $DayOfWeek.Length,($DayOfWeek -join ','))
return
}
}
}
'OnIdle'
{
$scheduleType = 'ONIDLE'
[void]$parameters.Add( '/I' )
[void]$parameters.Add( $OnIdle )
}
'OnEvent'
{
$modifier = $EventXPathQuery
}
'Xml*'
{
if( $PSCmdlet.ParameterSetName -eq 'Xml' )
{
$TaskXmlFilePath = 'Carbon+Install-ScheduledTask+{0}.xml' -f [IO.Path]::GetRandomFileName()
$TaskXmlFilePath = Join-Path -Path $env:TEMP -ChildPath $TaskXmlFilePath
$TaskXml.Save($TaskXmlFilePath)
}
$scheduleType = $null
$TaskXmlFilePath = Resolve-Path -Path $TaskXmlFilePath
if( -not $TaskXmlFilePath )
{
return
}
[void]$parameters.Add( '/XML' )
[void]$parameters.Add( $TaskXmlFilePath )
}
}
try
{
if( $modifier )
{
[void]$parameters.Add( '/MO' )
[void]$parameters.Add( $modifier )
}
if( $PSBoundParameters.ContainsKey('TaskToRun') )
{
[void]$parameters.Add( '/TR' )
[void]$parameters.Add( $TaskToRun )
}
if( $scheduleType )
{
[void]$parameters.Add( '/SC' )
[void]$parameters.Add( $scheduleType )
}
$parameterNameToSchtasksMap = @{
'StartTime' = '/ST';
'Interval' = '/RI';
'EndTime' = '/ET';
'Duration' = '/DU';
'StopAtEnd' = '/K';
'StartDate' = '/SD';
'EndDate' = '/ED';
'EventChannelName' = '/EC';
'Interactive' = '/IT';
'NoPassword' = '/NP';
'Force' = '/F';
'Delay' = '/DELAY';
}
foreach( $parameterName in $parameterNameToSchtasksMap.Keys )
{
if( -not $PSBoundParameters.ContainsKey( $parameterName ) )
{
continue
}
$schtasksParamName = $parameterNameToSchtasksMap[$parameterName]
$value = $PSBoundParameters[$parameterName]
if( $value -is [timespan] )
{
if( $parameterName -eq 'Duration' )
{
$totalHours = ($value.Days * 24) + $value.Hours
$value = '{0:0000}:{1:00}' -f $totalHours,$value.Minutes
}
elseif( $parameterName -eq 'Delay' )
{
$totalMinutes = ($value.Days * 24 * 60) + ($value.Hours * 60) + $value.Minutes
$value = '{0:0000}:{1:00}' -f $totalMinutes,$value.Seconds
}
else
{
$value = '{0:00}:{1:00}' -f $value.Hours,$value.Minutes
}
}
elseif( $value -is [datetime] )
{
$value = $value.ToString('MM/dd/yyyy')
}
[void]$parameters.Add( $schtasksParamName )
if( $value -isnot [switch] )
{
[void]$parameters.Add( $value )
}
}
if( $PSBoundParameters.ContainsKey('HighestAvailableRunLevel') -and $HighestAvailableRunLevel )
{
[void]$parameters.Add( '/RL' )
[void]$parameters.Add( 'HIGHEST' )
}
$originalEap = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
$paramLogString = $parameters -join ' '
if( $TaskCredential )
{
$paramLogString = $paramLogString -replace ([Text.RegularExpressions.Regex]::Escape($TaskCredential.GetNetworkCredential().Password)),'********'
}
Write-Verbose ('/TN {0} {1}' -f $Name,$paramLogString)
# Warnings get written by schtasks to the error stream. Fortunately, errors and warnings
# are prefixed with ERRROR and WARNING, so we can combine output/error streams and parse
# it later. We just have to make sure we remove any errors added to the $Error variable.
$errorCount = $Global:Error.Count
$output = schtasks /create /TN $Name $parameters 2>&1
if( $Global:Error.Count -gt $errorCount )
{
for( $idx = 0; $idx -lt ($Global:Error.Count - $errorCount); ++$idx )
{
$Global:Error.RemoveAt(0)
}
}
$ErrorActionPreference = $originalEap
$createFailed = $false
if( $LASTEXITCODE )
{
$createFailed = $true
}
$output | ForEach-Object {
if( $_ -match '\bERROR\b' )
{
Write-Error $_
}
elseif( $_ -match '\bWARNING\b' )
{
Write-Warning ($_ -replace '^WARNING: ','')
}
else
{
Write-Verbose $_
}
}
if( -not $createFailed )
{
Get-ScheduledTask -Name $Name
}
}
finally
{
if( $PSCmdlet.ParameterSetName -eq 'Xml' -and (Test-Path -Path $TaskXmlFilePath -PathType Leaf) )
{
Remove-Item -Path $TaskXmlFilePath -ErrorAction SilentlyContinue
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-Service
{
<#
.SYNOPSIS
Installs a Windows service.
.DESCRIPTION
`Install-Service` uses `sc.exe` to install a Windows service. If a service with the given name already exists, it is stopped, its configuration is updated to match the parameters passed in, and then re-started. Settings whose parameters are omitted are reset to their default values.
Beginning in Carbon 2.0, use the `PassThru` switch to return a `ServiceController` object for the new/updated service.
By default, the service is installed to run as `NetworkService`. Use the `Credential` parameter to run as a different account (if you don't have a `Credential` parameter, upgrade to Carbon 2.0 or use the `UserName` and `Password` parameters). This user will be granted the logon as a service right. To run as a system account other than `NetworkService`, provide just the account's name as the `UserName` parameter.
The minimum required information to install a service is its name and path.
[Managed service accounts and virtual accounts](http://technet.microsoft.com/en-us/library/dd548356.aspx) should be supported (we don't know how to test, so can't be sure). Simply omit the `-Password` parameter when providing a custom account name with the `-Username` parameter.
`Manual` services are not started. `Automatic` services are started after installation. If an existing manual service is running when configuration begins, it is re-started after re-configured.
The ability to provide service arguments/parameters via the `ArgumentList` parameter was added in Carbon 2.0.
.LINK
Carbon_Service
.LINK
New-Credential
.LINK
Uninstall-Service
.LINK
http://technet.microsoft.com/en-us/library/dd548356.aspx
.EXAMPLE
Install-Service -Name DeathStar -Path C:\ALongTimeAgo\InAGalaxyFarFarAway\DeathStar.exe
Installs the Death Star service, which runs the service executable at `C:\ALongTimeAgo\InAGalaxyFarFarAway\DeathStar.exe`. The service runs as `NetworkService` and will start automatically.
.EXAMPLE
Install-Service -Name DeathStar -Path C:\ALongTimeAgo\InAGalaxyFarFarAway\DeathStar.exe -StartupType Manual
Install the Death Star service to startup manually. You certainly don't want the thing roaming the galaxy, destroying thing willy-nilly, do you?
.EXAMPLE
Install-Service -Name DeathStar -Path C:\ALongTimeAgo\InAGalaxyFarFarAway\DeathStar.exe -Credential $tarkinCredentials
Installs the Death Star service to run as Grand Moff Tarkin, who is given the log on as a service right.
.EXAMPLE
Install-Service -Name DeathStar -Path C:\ALongTimeAgo\InAGalaxyFarFarAway\DeathStar.exe -Username SYSTEM
Demonstrates how to install a service to run as a system account other than `NetworkService`. Installs the DeathStart service to run as the local `System` account.
.EXAMPLE
Install-Service -Name DeathStar -Path C:\ALongTimeAgo\InAGalaxyFarFarAway\DeathStar.exe -OnFirstFailure RunCommand -RunCommandDelay 5000 -Command 'engage_hyperdrive.exe "Corruscant"' -OnSecondFailure Restart -RestartDelay 30000 -OnThirdFailure Reboot -RebootDelay 120000 -ResetFailureCount (60*60*24)
Demonstrates how to control the service's failure actions. On the first failure, Windows will run the `engage-hyperdrive.exe "Corruscant"` command after 5 seconds (`5,000` milliseconds). On the second failure, Windows will restart the service after 30 seconds (`30,000` milliseconds). On the third failure, Windows will reboot after two minutes (`120,000` milliseconds). The failure count gets reset once a day (`60*60*24` seconds).
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='NetworkServiceAccount')]
[OutputType([ServiceProcess.ServiceController])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams","")]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the service.
$Name,
[Parameter(Mandatory=$true)]
[string]
# The path to the service.
$Path,
[string[]]
# The arguments/startup parameters for the service. Added in Carbon 2.0.
$ArgumentList,
[ServiceProcess.ServiceStartMode]
# The startup type: automatic, manual, or disabled. Default is automatic.
$StartupType = [ServiceProcess.ServiceStartMode]::Automatic,
[Carbon.Service.FailureAction]
# What to do on the service's first failure. Default is to take no action.
$OnFirstFailure = [Carbon.Service.FailureAction]::TakeNoAction,
[Carbon.Service.FailureAction]
# What to do on the service's second failure. Default is to take no action.
$OnSecondFailure = [Carbon.Service.FailureAction]::TakeNoAction,
[Carbon.Service.FailureAction]
# What to do on the service' third failure. Default is to take no action.
$OnThirdFailure = [Carbon.Service.FailureAction]::TakeNoAction,
[int]
# How many seconds after which the failure count is reset to 0.
$ResetFailureCount = 0,
[int]
# How many milliseconds to wait before restarting the service. Default is 60,0000, or 1 minute.
$RestartDelay = 60000,
[int]
# How many milliseconds to wait before handling the second failure. Default is 60,000 or 1 minute.
$RebootDelay = 60000,
[Alias('Dependencies')]
[string[]]
# What other services does this service depend on?
$Dependency,
[string]
# The command to run when a service fails, including path to the command and arguments.
$Command,
[int]
# How many milliseconds to wait before running the failure command. Default is 0, or immediately.
$RunCommandDelay = 0,
[string]
# The service's description. If you don't supply a value, the service's existing description is preserved.
#
# The `Description` parameter was added in Carbon 2.0.
$Description,
[string]
# The service's display name. If you don't supply a value, the display name will set to Name.
#
# The `DisplayName` parameter was added in Carbon 2.0.
$DisplayName,
[Parameter(ParameterSetName='CustomAccount',Mandatory=$true)]
[string]
# The user the service should run as. Default is `NetworkService`.
$UserName,
[Parameter(ParameterSetName='CustomAccount',DontShow=$true)]
[string]
# OBSOLETE. The `Password` parameter will be removed in a future major version of Carbon. Use the `Credential` parameter instead.
$Password,
[Parameter(ParameterSetName='CustomAccountWithCredential',Mandatory=$true)]
[pscredential]
# The credential of the account the service should run as.
#
# The `Credential` parameter was added in Carbon 2.0.
$Credential,
[Switch]
# Update the service even if there are no changes.
$Force,
[Switch]
# Return a `System.ServiceProcess.ServiceController` object for the configured service.
$PassThru
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
function ConvertTo-FailureActionArg($action)
{
if( $action -eq 'Reboot' )
{
return "reboot/{0}" -f $RebootDelay
}
elseif( $action -eq 'Restart' )
{
return "restart/{0}" -f $RestartDelay
}
elseif( $action -eq 'RunCommand' )
{
return 'run/{0}' -f $RunCommandDelay
}
elseif( $action -eq 'TakeNoAction' )
{
return '""/0'
}
else
{
Write-Error "Service failure action '$action' not found/recognized."
return ''
}
}
if( $PSCmdlet.ParameterSetName -like 'CustomAccount*' )
{
if( $PSCmdlet.ParameterSetName -like '*WithCredential' )
{
$UserName = $Credential.UserName
}
elseif( $Password )
{
Write-Warning ('`Install-Service` function''s `Password` parameter is obsolete and will be removed in a future major version of Carbon. Please use the `Credential` parameter instead.')
$Credential = New-Credential -UserName $UserName -Password $Password
}
else
{
$Credential = $null
}
$identity = Resolve-Identity -Name $UserName
if( -not $identity )
{
Write-Error ("Identity '{0}' not found." -f $UserName)
return
}
}
else
{
$identity = Resolve-Identity "NetworkService"
}
if( -not (Test-Path -Path $Path -PathType Leaf) )
{
Write-Warning ('Service ''{0}'' executable ''{1}'' not found.' -f $Name,$Path)
}
else
{
$Path = Resolve-Path -Path $Path | Select-Object -ExpandProperty ProviderPath
}
if( $ArgumentList )
{
$binPathArg = Invoke-Command -ScriptBlock {
$Path
$ArgumentList
} |
ForEach-Object {
if( $_.Contains(' ') )
{
return '"{0}"' -f $_.Trim('"')
}
return $_
}
$binPathArg = $binPathArg -join ' '
}
else
{
$binPathArg = $Path
}
$doInstall = $false
if( -not $Force -and (Test-Service -Name $Name) )
{
Write-Debug -Message ('Service {0} exists. Checking if configuration has changed.' -f $Name)
$service = Get-Service -Name $Name
$serviceConfig = Get-ServiceConfiguration -Name $Name
$dependedOnServiceNames = $service.ServicesDependedOn | Select-Object -ExpandProperty 'Name'
if( $service.Path -ne $binPathArg )
{
Write-Verbose ('[{0}] Path {1} -> {2}' -f $Name,$serviceConfig.Path,$binPathArg)
$doInstall = $true
}
# DisplayName, if not set, defaults to the service name. This makes it a little bit tricky to update.
# If provided, make sure display name matches.
# If not provided, reset it to an empty/default value.
if( $PSBoundParameters.ContainsKey('DisplayName') )
{
if( $service.DisplayName -ne $DisplayName )
{
Write-Verbose ('[{0}] DisplayName {1} -> {2}' -f $Name,$service.DisplayName,$DisplayName)
$doInstall = $true
}
}
elseif( $service.DisplayName -ne $service.Name )
{
Write-Verbose ('[{0}] DisplayName {1} -> ' -f $Name,$service.DisplayName)
$doInstall = $true
}
if( $serviceConfig.FirstFailure -ne $OnFirstFailure )
{
Write-Verbose ('[{0}] OnFirstFailure {1} -> {2}' -f $Name,$serviceConfig.FirstFailure,$OnFirstFailure)
$doInstall = $true
}
if( $serviceConfig.SecondFailure -ne $OnSecondFailure )
{
Write-Verbose ('[{0}] OnSecondFailure {1} -> {2}' -f $Name,$serviceConfig.SecondFailure,$OnSecondFailure)
$doInstall = $true
}
if( $serviceConfig.ThirdFailure -ne $OnThirdFailure )
{
Write-Verbose ('[{0}] OnThirdFailure {1} -> {2}' -f $Name,$serviceConfig.ThirdFailure,$OnThirdFailure)
$doInstall = $true
}
if( $serviceConfig.ResetPeriod -ne $ResetFailureCount )
{
Write-Verbose ('[{0}] ResetFailureCount {1} -> {2}' -f $Name,$serviceConfig.ResetPeriod,$ResetFailureCount)
$doInstall = $true
}
$failureActions = $OnFirstFailure,$OnSecondFailure,$OnThirdFailure
if( ($failureActions | Where-Object { $_ -eq [Carbon.Service.FailureAction]::Reboot }) -and $serviceConfig.RebootDelay -ne $RebootDelay )
{
Write-Verbose ('[{0}] RebootDelay {1} -> {2}' -f $Name,$serviceConfig.RebootDelay,$RebootDelay)
$doInstall = $true
}
if( ($failureActions | Where-Object { $_ -eq [Carbon.Service.FailureAction]::Restart }) -and $serviceConfig.RestartDelay -ne $RestartDelay)
{
Write-Verbose ('[{0}] RestartDelay {1} -> {2}' -f $Name,$serviceConfig.RestartDelay,$RestartDelay)
$doInstall = $true
}
if( $failureActions | Where-Object { $_ -eq [Carbon.Service.FailureAction]::RunCommand } )
{
if( $serviceConfig.FailureProgram -ne $Command )
{
Write-Verbose ('[{0}] Command {1} -> {2}' -f $Name,$serviceConfig.FailureProgram,$Command)
$doInstall = $true
}
if( $serviceConfig.RunCommandDelay -ne $RunCommandDelay )
{
Write-Verbose ('[{0}] RunCommandDelay {1} -> {2}' -f $Name,$serviceConfig.RunCommandDelay,$RunCommandDelay)
$doInstall = $true
}
}
if( $service.StartMode -ne $StartupType )
{
Write-Verbose ('[{0}] StartupType {1} -> {2}' -f $Name,$serviceConfig.StartType,$StartupType)
$doInstall = $true
}
if( ($Dependency | Where-Object { $dependedOnServiceNames -notcontains $_ }) -or `
($dependedOnServiceNames | Where-Object { $Dependency -notcontains $_ }) )
{
Write-Verbose ('[{0}] Dependency {1} -> {2}' -f $Name,($dependedOnServiceNames -join ','),($Dependency -join ','))
$doInstall = $true
}
if( $Description -and $serviceConfig.Description -ne $Description )
{
Write-Verbose ('[{0}] Description {1} -> {2}' -f $Name,$serviceConfig.Description,$Description)
$doInstall = $true
}
if( $PSCmdlet.ParameterSetName -like 'CustomAccount*' -and $serviceConfig.UserName -ne $identity.FullName )
{
Write-Verbose ('[{0}] UserName {1} -> {2}' -f $Name,$serviceConfig.UserName,$identity.FullName)
$doinstall = $true
}
}
else
{
$doInstall = $true
}
if( -not $doInstall )
{
Write-Debug -Message ('Skipping {0} service configuration: settings unchanged.' -f $Name)
if( $PassThru )
{
Get-Service -Name $Name -ErrorAction Ignore
}
return
}
if( $Dependency )
{
$missingDependencies = $false
$Dependency |
ForEach-Object {
if( -not (Test-Service -Name $_) )
{
Write-Error ('Dependent service {0} not found.' -f $_)
$missingDependencies = $true
}
}
if( $missingDependencies )
{
return
}
}
$sc = Join-Path $env:WinDir system32\sc.exe -Resolve
$startArg = 'auto'
if( $StartupType -eq 'Manual' )
{
$startArg = 'demand'
}
elseif( $StartupType -eq 'Disabled' )
{
$startArg = 'disabled'
}
$passwordArgName = ''
$passwordArgValue = ''
if( $PSCmdlet.ParameterSetName -like 'CustomAccount*' )
{
if( $Credential )
{
$passwordArgName = 'password='
$passwordArgValue = $Credential.GetNetworkCredential().Password
}
if( $PSCmdlet.ShouldProcess( $identity.FullName, "grant the log on as a service right" ) )
{
Grant-Privilege -Identity $identity.FullName -Privilege SeServiceLogonRight
}
}
if( $PSCmdlet.ShouldProcess( $Path, ('grant {0} ReadAndExecute permissions' -f $identity.FullName) ) )
{
Grant-Permission -Identity $identity.FullName -Permission ReadAndExecute -Path $Path
}
$service = Get-Service -Name $Name -ErrorAction Ignore
$operation = 'create'
$serviceIsRunningStatus = @(
[ServiceProcess.ServiceControllerStatus]::Running,
[ServiceProcess.ServiceControllerStatus]::StartPending
)
$restartService = ($StartupType -eq [ServiceProcess.ServiceStartMode]::Automatic)
if( $service )
{
$restartService = ( $restartService -or ($serviceIsRunningStatus -contains $service.Status) )
if( $service.CanStop )
{
Stop-Service -Name $Name -Force -ErrorAction Ignore
if( $? )
{
$service.WaitForStatus( 'Stopped' )
}
}
if( -not ($service.Status -eq [ServiceProcess.ServiceControllerStatus]::Stopped) )
{
Write-Warning "Unable to stop service '$Name' before applying config changes. You may need to restart this service manually for any changes to take affect."
}
$operation = 'config'
}
$dependencyArgValue = '""'
if( $Dependency )
{
$dependencyArgValue = $Dependency -join '/'
}
$displayNameArgName = 'DisplayName='
$displayNameArgValue = '""'
if( $DisplayName )
{
$displayNameArgValue = $DisplayName
}
$binPathArg = $binPathArg -replace '"','\"'
if( $PSCmdlet.ShouldProcess( "$Name [$Path]", "$operation service" ) )
{
& $sc $operation $Name binPath= $binPathArg start= $startArg obj= $identity.FullName $passwordArgName $passwordArgValue depend= $dependencyArgValue $displayNameArgName $displayNameArgValue |
Write-Verbose
$scExitCode = $LastExitCode
if( $scExitCode -ne 0 )
{
$reason = net helpmsg $scExitCode 2>$null | Where-Object { $_ }
Write-Error ("Falied to {0} service '{1}'. {2} returned exit code {3}: {4}" -f $operation,$Name,$sc,$scExitCode,$reason)
return
}
if( $Description )
{
& $sc 'description' $Name $Description | Write-Verbose
$scExitCode = $LastExitCode
if( $scExitCode -ne 0 )
{
$reason = net helpmsg $scExitCode 2>$null | Where-Object { $_ }
Write-Error ("Falied to set {0} service's description. {1} returned exit code {2}: {3}" -f $Name,$sc,$scExitCode,$reason)
return
}
}
}
$firstAction = ConvertTo-FailureActionArg $OnFirstFailure
$secondAction = ConvertTo-FailureActionArg $OnSecondFailure
$thirdAction = ConvertTo-FailureActionArg $OnThirdFailure
if( -not $Command )
{
$Command = '""'
}
if( $PSCmdlet.ShouldProcess( $Name, "setting service failure actions" ) )
{
& $sc failure $Name reset= $ResetFailureCount actions= $firstAction/$secondAction/$thirdAction command= $Command |
Write-Verbose
$scExitCode = $LastExitCode
if( $scExitCode -ne 0 )
{
$reason = net helpmsg $scExitCode 2>$null | Where-Object { $_ }
Write-Error ("Failed to set {0} service's failure actions. {1} returned exit code {2}: {3}" -f $Name,$sc,$scExitCode,$reason)
return
}
}
if( $restartService )
{
if( $PSCmdlet.ShouldProcess( $Name, 'start service' ) )
{
Start-Service -Name $Name -ErrorAction $ErrorActionPreference
if( (Get-Service -Name $Name).Status -ne [ServiceProcess.ServiceControllerStatus]::Running )
{
if( $PSCmdlet.ParameterSetName -like 'CustomAccount*' -and -not $Credential )
{
Write-Warning ('Service ''{0}'' didn''t start and you didn''t supply a password to Install-Service. Is ''{1}'' a managed service account or virtual account? (See http://technet.microsoft.com/en-us/library/dd548356.aspx.) If not, please use the `Credential` parameter to pass the account''s credentials.' -f $Name,$UserName)
}
else
{
Write-Warning ('Failed to re-start service ''{0}''.' -f $Name)
}
}
}
}
else
{
Write-Verbose ('Not re-starting {0} service. Its startup type is {1} and it wasn''t running when configuration began.' -f $Name,$StartupType)
}
if( $PassThru )
{
Get-Service -Name $Name -ErrorAction Ignore
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Install-User
{
<#
.SYNOPSIS
Installs a *local* user account.
.DESCRIPTION
`Install-User` creates a new *local* user account, or updates an existing *local* user account.
Returns the user if `-PassThru` switch is used. The object returned, an instance of `System.DirectoryServices.AccountManagement.UserPrincipal`, uses external resources, which means it can leak memory when garbage collected. When you're done using the user object you get, call its `Dispose()` method so its external resources are cleaned up properly.
The `UserCannotChangePassword` and `PasswordExpires` switches were added in Carbon 2.0.
.OUTPUTS
System.DirectoryServices.AccountManagement.UserPrincipal.
.LINK
Get-User
.LINK
New-Credential
.LINK
Test-User
.LINK
Uninstall-User
.EXAMPLE
Install-User -Credential $lukeCredentials -Description "Luke Skywalker's account."
Creates a new `LSkywalker` user account with the given password and description. Luke's password is set to never expire.
.EXAMPLE
Install-User -Credential $lukeCredentials -UserCannotChangePassword -PasswordExpires
Demonstrates how to create an account for a user who cannot change his password and whose password will expire.
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='WithUserNameAndPassword')]
[OutputType([System.DirectoryServices.AccountManagement.UserPrincipal])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams","")]
param(
[Parameter(Mandatory=$true,ParameterSetName='WithUserNameAndPassword',DontShow=$true)]
[ValidateLength(1,20)]
[string]
# OBSOLETE. The `UserName` parameter will be removed in a future major version of Carbon. Use the `Credential` parameter instead.
$UserName,
[Parameter(Mandatory=$true,ParameterSetName='WithUserNameAndPassword',DontShow=$true)]
[string]
# OBSOLETE. The `Password` parameter will be removed in a future major version of Carbon. Use the `Credential` parameter instead.
$Password,
[Parameter(Mandatory=$true,ParameterSetName='WithCredential')]
[pscredential]
# The user's credentials.
#
# The `Credential` parameter was added in Carbon 2.0.
$Credential,
[string]
# A description of the user.
$Description,
[string]
# The full name of the user.
$FullName,
[Switch]
# Prevent the user from changing his password. New in Carbon 2.0.
$UserCannotChangePassword,
[Switch]
# Set to true if the user's password should expire. New in Carbon 2.0.
$PasswordExpires,
[Switch]
# Return the user. New in Carbon 2.0.
$PassThru
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSCmdlet.ParameterSetName -eq 'WithCredential' )
{
$UserName = $Credential.UserName
}
$ctx = New-Object 'DirectoryServices.AccountManagement.PrincipalContext' ([DirectoryServices.AccountManagement.ContextType]::Machine)
$user = [DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity( $ctx, $UserName )
try
{
$operation = 'update'
if( -not $user )
{
$operation = 'create'
$user = New-Object 'DirectoryServices.AccountManagement.UserPrincipal' $ctx
$creating = $true
}
$user.SamAccountName = $UserName
$user.DisplayName = $FullName
$user.Description = $Description
$user.UserCannotChangePassword = $UserCannotChangePassword
$user.PasswordNeverExpires = -not $PasswordExpires
if( $PSCmdlet.ParameterSetName -eq 'WithUserNameAndPassword' )
{
Write-Warning ('Install-User function''s `UserName` and `Password` parameters are obsolete and will be removed in a future version of Carbon. Please use the `Credential` parameter instead.')
$user.SetPassword( $Password )
}
else
{
$user.SetPassword( $Credential.GetNetworkCredential().Password )
}
if( $PSCmdlet.ShouldProcess( $Username, "$operation local user" ) )
{
$user.Save()
}
if( $PassThru )
{
return $user
}
}
finally
{
if( -not $PassThru )
{
$user.Dispose()
$ctx.Dispose()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This function should only be available if the Windows PowerShell v3.0 Server Manager cmdlets aren't already installed.
if( -not (Get-Command -Name 'Get-WindowsFeature*' | Where-Object { $_.ModuleName -ne 'Carbon' }) )
{
function Install-WindowsFeature
{
<#
.SYNOPSIS
Installs an optional Windows component/feature.
.DESCRIPTION
This function will install Windows features. Note that the name of these features can differ between different versions of Windows. Use `Get-WindowsFeature` to get the list of features on your operating system.
**This function is not available on Windows 8/2012.**
.LINK
Get-WindowsFeature
.LINK
Test-WindowsFeature
.LINK
Uninstall-WindowsFeature
.EXAMPLE
Install-WindowsFeature -Name TelnetClient
Installs Telnet.
.EXAMPLE
Install-WindowsFeature -Name TelnetClient,TFTP
Installs Telnet and TFTP
.EXAMPLE
Install-WindowsFeature -Iis
Installs IIS.
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='ByName')]
param(
[Parameter(Mandatory=$true,ParameterSetName='ByName')]
[string[]]
# The components to enable/install. Feature names are case-sensitive.
[Alias('Features')]
$Name,
[Parameter(ParameterSetName='ByFlag')]
[Switch]
# Installs IIS.
$Iis,
[Parameter(ParameterSetName='ByFlag')]
[Switch]
# Installs IIS's HTTP redirection feature.
$IisHttpRedirection,
[Parameter(ParameterSetName='ByFlag')]
[Switch]
# Installs MSMQ.
$Msmq,
[Parameter(ParameterSetName='ByFlag')]
[Switch]
# Installs MSMQ HTTP support.
$MsmqHttpSupport,
[Parameter(ParameterSetName='ByFlag')]
[Switch]
# Installs MSMQ Active Directory Integration.
$MsmqActiveDirectoryIntegration
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Write-Warning -Message ('Install-WindowsFeature is obsolete and will be removed in a future major version of Carbon.')
if( -not (Assert-WindowsFeatureFunctionsSupported) )
{
return
}
if( $pscmdlet.ParameterSetName -eq 'ByFlag' )
{
$Name = Resolve-WindowsFeatureName -Name $PSBoundParameters.Keys
}
$componentsToInstall = $Name |
ForEach-Object {
if( (Test-WindowsFeature -Name $_) )
{
$_
}
else
{
Write-Error ('Windows feature {0} not found.' -f $_)
}
} |
Where-Object { -not (Test-WindowsFeature -Name $_ -Installed) }
if( -not $componentsToInstall -or $componentsToInstall.Length -eq 0 )
{
return
}
if( $pscmdlet.ShouldProcess( "Windows feature(s) '$componentsToInstall'", "install" ) )
{
if( $useServerManager )
{
servermanagercmd.exe -install $componentsToInstall
}
else
{
$featuresArg = $componentsToInstall -join ';'
& ocsetup.exe $featuresArg
$ocsetup = Get-Process 'ocsetup' -ErrorAction SilentlyContinue
if( -not $ocsetup )
{
Write-Error "Unable to find process 'ocsetup'. It looks like the Windows Optional Component setup program didn't start."
return
}
$ocsetup.WaitForExit()
}
}
}
Set-Alias -Name 'Install-WindowsFeatures' -Value 'Install-WindowsFeature'
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Invoke-AppCmd
{
<#
.SYNOPSIS
OBSOLETE. Will be removed in a future major version of Carbon. Use `Get-IisConfigurationSection` with the `Microsoft.Web.Administration` API instead.
.DESCRIPTION
OBSOLETE. Will be removed in a future major version of Carbon. Use `Get-IisConfigurationSection` with the `Microsoft.Web.Administration` API instead.
.EXAMPLE
Get-IisConfigurationSection -SiteName 'Peanuts' -Section 'system.webServer'
Demonstrates the `Invoke-AppCmd` is OBSOLETE and will be removed in a future major version of Carbon. Use `Get-IisConfigurationSection` with the `Microsoft.Web.Administration` API instead.
#>
[CmdletBinding()]
param(
[Parameter(ValueFromRemainingArguments=$true)]
# The arguments to pass to appcmd.
$AppCmdArgs
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Write-Warning ('Invoke-AppCmd is obsolete and will be removed in a future major version of Carbon. Use Carbon''s IIS functions, or `Get-IisConfigurationSection` to get `ConfigurationElement` objects to manipulate using the `Microsoft.Web.Administration` API.')
Write-Verbose ($AppCmdArgs -join " ")
& (Join-Path $env:SystemRoot 'System32\inetsrv\appcmd.exe') $AppCmdArgs
if( $LastExitCode -ne 0 )
{
Write-Error "``AppCmd $($AppCmdArgs)`` exited with code $LastExitCode."
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Invoke-ConsoleCommand
{
<#
.SYNOPSIS
INTERNAL.
.DESCRIPTION
INTERNAL.
.EXAMPLE
INTERNAL.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The target of the action.
$Target,
[Parameter(Mandatory=$true)]
[string]
# The action/command being performed.
$Action,
[Parameter(Mandatory=$true)]
[scriptblock]
# The command to run.
$ScriptBlock
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not $PSCmdlet.ShouldProcess( $Target, $Action ) )
{
return
}
$output = Invoke-Command -ScriptBlock $ScriptBlock
if( $LASTEXITCODE )
{
$output = $output -join [Environment]::NewLine
Write-Error ('Failed action ''{0}'' on target ''{1}'' (exit code {2}): {3}' -f $Action,$Target,$LASTEXITCODE,$output)
}
else
{
$output | Where-Object { $_ -ne $null } | Write-Verbose
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Invoke-PowerShell
{
<#
.SYNOPSIS
Invokes a script block in a separate powershell.exe process.
.DESCRIPTION
If using PowerShell v2.0, the invoked PowerShell process can run under the .NET 4.0 CLR (using `v4.0` as the value to the Runtime parameter).
If using PowerShell v3.0, you can *only* run script blocks under a `v4.0` CLR. PowerShell converts script blocks to an encoded command, and when running encoded commands, PowerShell doesn't allow the `-Version` parameter for running PowerShell under a different version. To run code under a .NET 2.0 CLR from PowerShell 3, use the `FilePath` parameter to run a specfic script.
This function launches a PowerShell process that matches the architecture of the *operating system*. On 64-bit operating systems, you can run under 32-bit PowerShell by specifying the `x86` switch).
PowerShell's execution policy has to be set seperately in all architectures (i.e. x86 and x64), so you may get an error message about script being disabled. Use the `-ExecutionPolicy` parameter to set a temporary execution policy when running a script.
.EXAMPLE
Invoke-PowerShell -Command { $PSVersionTable }
Runs a separate PowerShell process which matches the architecture of the operating system, returning the $PSVersionTable from that process. This will fail under 32-bit PowerShell on a 64-bit operating system.
.EXAMPLE
Invoke-PowerShell -Command { $PSVersionTable } -x86
Runs a 32-bit PowerShell process, return the $PSVersionTable from that process.
.EXAMPLE
Invoke-PowerShell -Command { $PSVersionTable } -Runtime v4.0
Runs a separate PowerShell process under the v4.0 .NET CLR, returning the $PSVersionTable from that process. Should return a CLRVersion of `4.0`.
.EXAMPLE
Invoke-PowerShell -FilePath C:\Projects\Carbon\bin\Set-DotNetConnectionString.ps1 -ArgumentList '-Name','myConn','-Value',"'data source=.\DevDB;Integrated Security=SSPI;'"
Runs the `Set-DotNetConnectionString.ps1` script with `ArgumentList` as arguments/parameters.
Note that you have to double-quote any arguments with spaces. Otherwise, the argument gets interpreted as multiple arguments.
.EXAMPLE
Invoke-PowerShell -FilePath Get-PsVersionTable.ps1 -x86 -ExecutionPolicy RemoteSigned
Shows how to run powershell.exe with a custom executin policy, in case the running of scripts is disabled.
#>
[CmdletBinding(DefaultParameterSetName='ScriptBlock')]
param(
[Parameter(Mandatory=$true,ParameterSetName='ScriptBlock')]
[Alias('Command')]
[ScriptBlock]
# The command to run.
$ScriptBlock,
[Parameter(Mandatory=$true,ParameterSetName='FilePath')]
[string]
# The script to run.
$FilePath,
[object[]]
[Alias('Args')]
# Any arguments to pass to the command/scripts.
$ArgumentList,
[string]
# Determines how output from the PowerShel command is formatted
$OutputFormat,
[Parameter(ParameterSetName='FilePath')]
[Microsoft.PowerShell.ExecutionPolicy]
# The execution policy to use when running a script. By default, execution policies are set to `Restricted`. If running an architecture of PowerShell whose execution policy isn't set, `Invoke-PowerShell` will fail.
$ExecutionPolicy,
[Switch]
# Run the x86 (32-bit) version of PowerShell, otherwise the version which matches the OS architecture is run, *regardless of the architecture of the currently running process*.
$x86,
[string]
[ValidateSet('v2.0','v4.0')]
# The CLR to use. Must be one of `v2.0` or `v4.0`. Default is the current PowerShell runtime.
$Runtime
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$powerShellv3Installed = Test-Path -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3
$currentRuntime = 'v{0}.0' -f $PSVersionTable.CLRVersion.Major
if( $powerShellv3Installed )
{
$currentRuntime = 'v4.0'
}
# Check that the selected runtime is installed.
if( $PSBoundParameters.ContainsKey('Runtime') )
{
$runtimeInstalled = switch( $Runtime )
{
'v2.0' { Test-DotNet -V2 }
'v4.0' { Test-DotNet -V4 -Full }
default { Write-Error ('Unknown runtime value ''{0}''.' -f $Runtime) }
}
if( -not $runtimeInstalled )
{
Write-Error ('.NET {0} not found.' -f $Runtime)
return
}
}
if( -not $Runtime )
{
$Runtime = $currentRuntime
}
if( $PSCmdlet.ParameterSetName -eq 'ScriptBlock' -and `
$Host.Name -eq 'Windows PowerShell ISE Host' -and `
$Runtime -eq 'v2.0' -and `
$powerShellv3Installed )
{
Write-Error ('The PowerShell ISE v{0} can''t run script blocks under .NET {1}. Please run from the PowerShell console, or save your script block into a file and re-run Invoke-PowerShell using the `FilePath` parameter.' -f `
$PSVersionTable.PSVersion,$Runtime)
return
}
$comPlusAppConfigEnvVarName = 'COMPLUS_ApplicationMigrationRuntimeActivationConfigPath'
$activationConfigDir = Join-Path $env:TEMP ([IO.Path]::GetRandomFileName())
$activationConfigPath = Join-Path $activationConfigDir powershell.exe.activation_config
$originalCOMAppConfigEnvVar = [Environment]::GetEnvironmentVariable( $comPlusAppConfigEnvVarName )
if( -not $powerShellv3Installed -and $currentRuntime -ne $Runtime )
{
$null = New-Item -Path $activationConfigDir -ItemType Directory
@"
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="{0}" />
</startup>
</configuration>
"@ -f $Runtime | Out-File -FilePath $activationConfigPath -Encoding OEM
Set-EnvironmentVariable -Name $comPlusAppConfigEnvVarName -Value $activationConfigDir -ForProcess
}
$params = @{ }
if( $x86 )
{
$params.x86 = $true
}
try
{
$psPath = Get-PowerShellPath @params
if( $ArgumentList -eq $null )
{
$ArgumentList = @()
}
$powerShellArgs = @( )
if( $powerShellv3Installed -and $Runtime -eq 'v2.0' )
{
$powerShellArgs += '-Version'
$powerShellArgs += '2.0'
}
$powerShellArgs += '-NoProfile'
if( $OutputFormat )
{
$powerShellArgs += '-OutputFormat'
$powerShellArgs += $OutputFormat
}
if( $PSCmdlet.ParameterSetName -eq 'ScriptBlock' )
{
& $psPath $powerShellArgs -Command $ScriptBlock -Args $ArgumentList
}
else
{
if( $ExecutionPolicy )
{
$powerShellArgs += '-ExecutionPolicy'
$powerShellArgs += $ExecutionPolicy
}
Write-Debug ('{0} {1} -Command {2} {3}' -f $psPath,($powerShellArgs -join " "),$FilePath,($ArgumentList -join ' '))
& $psPath $powerShellArgs -File $FilePath $ArgumentList
Write-Debug ('LASTEXITCODE: {0}' -f $LASTEXITCODE)
}
}
finally
{
if( Test-Path -Path $activationConfigDir -PathType Leaf )
{
Remove-Item -Path $activationConfigDir -Recurse -Force
}
if( Test-Path -Path env:$comPlusAppConfigEnvVarName )
{
if( $originalCOMAppConfigEnvVar )
{
Set-EnvironmentVariable -Name $comPlusAppConfigEnvVarName -Value $originalCOMAppConfigEnvVar -ForProcess
}
else
{
Remove-EnvironmentVariable -Name $comPlusAppConfigEnvVarName -ForProcess
}
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Join-IisVirtualPath
{
<#
.SYNOPSIS
Combines a path and a child path for an IIS website, application, virtual directory into a single path.
.DESCRIPTION
Removes extra slashes. Converts backward slashes to forward slashes. Relative portions are not removed. Sorry.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Join-IisVirtualPath 'SiteName' 'Virtual/Path'
Demonstrates how to join two IIS paths together. REturns `SiteName/Virtual/Path`.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=0)]
[string]
# The parent path.
$Path,
[Parameter(Position=1)]
[string]
$ChildPath
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $ChildPath )
{
$Path = Join-Path -Path $Path -ChildPath $ChildPath
}
$Path.Replace('\', '/').Trim('/')
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Lock-IisConfigurationSection
{
<#
.SYNOPSIS
Locks an IIS configuration section so that it can't be modified/overridden by individual websites.
.DESCRIPTION
Locks configuration sections globally so they can't be modified by individual websites. For a list of section paths, run
C:\Windows\System32\inetsrv\appcmd.exe lock config /section:?
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Lock-IisConfigurationSection -SectionPath 'system.webServer/security/authentication/basicAuthentication'
Locks the `basicAuthentication` configuration so that sites can't override/modify those settings.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string[]]
# The path to the section to lock. For a list of sections, run
#
# C:\Windows\System32\inetsrv\appcmd.exe unlock config /section:?
$SectionPath
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$SectionPath |
ForEach-Object {
$section = Get-IisConfigurationSection -SectionPath $_
$section.OverrideMode = 'Deny'
if( $pscmdlet.ShouldProcess( $_, 'locking IIS configuration section' ) )
{
$section.CommitChanges()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function New-Credential
{
<#
.SYNOPSIS
Creates a new `PSCredential` object from a given username and password.
.DESCRIPTION
`New-Credential` will create a credential for you from a username and password, converting a password stored as a `String` into a `SecureString`.
PowerShell commands use `PSCredential` objects instead of username/password. Although Microsoft recommends using `Get-Credential` to get credentials, when automating installs, there's usually no one around to answer that prompt, so secrets are often pulled from encrypted stores.
Beginning with Carbon 2.0, you can pass a `SecureString` as the value for the `Password` parameter.
Beginning with Carbon 2.0, you can pipe passwords to `New-Credential`, e.g.
Read-EncrptedPassword | Unprotect-String | New-Credential -Username 'fubar'
We do *not* recommend passing plaintext passwords around. Beginning ing with Carbon 2.0, you can use `Unprotect-String` to decrypt secrets securely to `SecureStrings` and then use those secure strings with `New-Credential` to create a credential.
.LINK
Protect-String
.LINK
Unprotect-String
.OUTPUTS
System.Management.Automation.PSCredential.
.EXAMPLE
New-Credential -User ENTERPRISE\picard -Password 'earlgrey'
Creates a new credential object for Captain Picard.
.EXAMPLE
Read-EncryptedPassword | Unprotect-String | New-Credential -UserName 'ENTERPRISE\picard'
Demonstrates how to securely decrypt a secret into a new credential object.
#>
[CmdletBinding()]
[OutputType([Management.Automation.PSCredential])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams","")]
param(
[Alias('User')]
[string]
# The username. Beginning with Carbon 2.0, this parameter is optional. Previously, this parameter was required.
$UserName,
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
# The password. Can be a `[string]` or a `[System.Security.SecureString]`.
$Password
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
}
process
{
if( $Password -is [string] )
{
$Password = ConvertTo-SecureString -AsPlainText -Force -String $Password
}
elseif( $Password -isnot [securestring] )
{
Write-Error ('Value for Password parameter must be a [String] or [System.Security.SecureString]. You passed a [{0}].' -f $Password.GetType())
return
}
return New-Object 'Management.Automation.PsCredential' $UserName,$Password
}
end
{
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function New-Junction
{
<#
.SYNOPSIS
Creates a new junction.
.DESCRIPTION
Creates a junction given by `-Link` which points to the path given by `-Target`. If something already exists at `Link`, an error is written.
Returns a `System.IO.DirectoryInfo` object for the junction, if one is created.
.OUTPUTS
System.IO.DirectoryInfo.
.LINK
Install-Junction
.LINK
Remove-Junction
.EXAMPLE
New-Junction -Link 'C:\Windows\system32Link' -Target 'C:\Windows\system32'
Creates the `C:\Windows\system32Link` directory, which points to `C:\Windows\system32`.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Alias("Junction")]
[string]
# The new junction to create
$Link,
[Parameter(Mandatory=$true)]
[string]
# The target of the junction, i.e. where the junction will point to
$Target
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( Test-Path -LiteralPath $Link -PathType Container )
{
Write-Error "'$Link' already exists."
}
else
{
Write-Verbose -Message "Creating junction $Link <=> $Target"
[Carbon.IO.JunctionPoint]::Create( $Link, $Target, $false )
if( Test-Path $Link -PathType Container )
{
Get-Item $Link
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function New-RsaKeyPair
{
<#
.SYNOPSIS
Generates a public/private RSA key pair.
.DESCRIPTION
The `New-RsaKeyPair` function uses the `certreq.exe` program to generate an RSA public/private key pair suitable for use in encrypting/decrypting CMS messages, credentials in DSC resources, etc. It uses the following `.inf` file as input (taken from the first example in the help for the `Protect-CmsMessage` cmdlet):
[Version]
Signature = "$Windows NT$"
[Strings]
szOID_ENHANCED_KEY_USAGE = "2.5.29.37"
szOID_DOCUMENT_ENCRYPTION = "1.3.6.1.4.1.311.80.1"
[NewRequest]
Subject = $Subject
MachineKeySet = false
KeyLength = $Length
KeySpec = AT_KEYEXCHANGE
HashAlgorithm = $Algorithm
Exportable = true
RequestType = Cert
KeyUsage = "CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE"
ValidityPeriod = Days
ValidityPeriodUnits =
[Extensions]
%szOID_ENHANCED_KEY_USAGE% = "{{text}}%szOID_DOCUMENT_ENCRYPTION%"
You can control the subject (via the `-Subject` parameter), key length (via the `-Length` parameter), the hash algorithm (via the `-Algorithm` parameter), and the expiration date of the keys (via the `-ValidTo` parameter). The subject is always required and should begin with "CN=". The length, hash algorithm, and expiration date are optional, and default to `4096`, `sha512`, and `12/31/9999`, respectively.
The `certreq.exe` command stores the private key in the current user's `My` certificate store. This function exports that private key to a file and removes it from the current user's `My` store. The private key is protected with the password provided via the `-Password` parameter. If you don't provide a password, you will be prompted for one. To not protect the private key with a password, pass `$null` as the value of the `-Password` parameter.
The public key is saved as an X509Certificate. The private key is saved as a PFX file. Both can be loaded by .NET's `X509Certificate` class. Returns `System.IO.FileInfo` objects for the public and private key, in that order.
Before Carbon 2.1, this function used the `makecert.exe` and `pvk2pfx.exe` programs, from the Windows SDK. These programs prompt multiple times for the private key password, so if you're using a version before 2.1, you can't run this function non-interactively.
.OUTPUTS
System.IO.FileInfo
.LINK
Get-Certificate
.LINK
Install-Certificate
.EXAMPLE
New-RsaKeyPair -Subject 'CN=MyName' -PublicKeyFile 'MyName.cer' -PrivateKeyFile 'MyName.pfx' -Password $secureString
Demonstrates the minimal parameters needed to generate a key pair. The key will use a sha512 signing algorithm, have a length of 4096 bits, and expire on `12/31/9999`. The public key will be saved in the current directory as `MyName.cer`. The private key will be saved to the current directory as `MyName.pfx` and protected with password in `$secureString`.
.EXAMPLE
New-RsaKeyPair -Subject 'CN=MyName' -PublicKeyFile 'MyName.cer' -PrivateKeyFile 'MyName.pfx' -Password $null
Demonstrates how to save the private key unprotected (i.e. without a password). You must set the password to `$null`. This functionality was introduced in Carbon 2.1.
.EXAMPLE
New-RsaKeyPair -Subject 'CN=MyName' -PublicKeyFile 'MyName.cer' -PrivateKeyFile 'MyName.pfx' -Algorithm 'sha1' -ValidTo (Get-Date -Year 2015 -Month 12 -Day 31) -Length 1024 -Password $secureString
Demonstrates how to use all the parameters to create a truly customized key pair. The generated certificate will use the sha1 signing algorithm, becomes effective 1/1/2015, expires 12/31/2015, and is 1024 bits in length.
#>
[CmdletBinding()]
[OutputType([IO.FileInfo])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams","")]
param(
[Parameter(Mandatory=$true,Position=0)]
[ValidatePattern('^CN=')]
[string]
# The key's subject. Should be of the form `CN=Name,OU=Name,O=SuperMagicFunTime,ST=OR,C=US`. Only the `CN=Name` part is required.
$Subject,
[ValidateSet('md5','sha1','sha256','sha384','sha512')]
[string]
# The signature algorithm. Default is `sha512`.
$Algorithm = 'sha512',
[Parameter(DontShow=$true)]
[DateTime]
# The date/time the keys will become valid. Default is now.
#
# This parameter was made obsolete in Carbon 2.1.
$ValidFrom = (Get-Date),
[DateTime]
# The date/time the keys should expire. Default is `DateTime::MaxValue`.
$ValidTo = ([DateTime]::MaxValue),
[int]
# The length, in bits, of the generated key length. Default is `4096`.
$Length = 4096,
[Parameter(DontShow=$true)]
[ValidateSet('commercial','individual')]
[string]
# The signing authority of the certificate. Must be `commercial` (for certificates used by commercial software publishers) or `individual`, for certificates used by individual software publishers. Default is `individual`.
#
# This parameter was made obsolete in Carbon 2.1.
$Authority = 'individual',
[Parameter(Mandatory=$true,Position=1)]
[string]
# The file where the public key should be stored. Saved as an X509 certificate.
$PublicKeyFile,
[Parameter(Mandatory=$true,Position=2)]
[string]
# The file where the private key should be stored. The private key will be saved as an X509 certificate in PFX format and will include the public key.
$PrivateKeyFile,
[securestring]
# The password for the private key. If one is not provided, you will be prompted for one. Pass `$null` to not protect your private key with a password.
#
# This parameter was introduced in Carbon 2.1.
$Password,
[Switch]
# Overwrites `PublicKeyFile` and/or `PrivateKeyFile`, if they exist.
$Force
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSBoundParameters.ContainsKey('ValidFrom') )
{
Write-Warning -Message ('New-RsaKeyPair: The -ValidFrom parameter is obsolete and will be removed in a future version of Carbon. Please remove usages of this parameter.')
}
if( $PSBoundParameters.ContainsKey('Authority') )
{
Write-Warning -Message ('New-RsaKeyPair: The -Authority parameter is obsolete and will be removed in a future version of Carbon. Please remove usages of this parameter.')
}
function Resolve-KeyPath
{
param(
[Parameter(Mandatory=$true)]
[string]
$Path
)
Set-StrictMode -Version 'Latest'
$Path = Resolve-FullPath -Path $Path
if( (Test-Path -Path $Path -PathType Leaf) )
{
if( -not $Force )
{
Write-Error ('File ''{0}'' exists. Use the -Force switch to overwrite.' -f $Path)
return
}
}
else
{
$root = Split-Path -Parent -Path $Path
if( -not (Test-Path -Path $root -PathType Container) )
{
New-Item -Path $root -ItemType 'Directory' -Force | Out-Null
}
}
return $Path
}
$PublicKeyFile = Resolve-KeyPath -Path $PublicKeyFile
if( -not $PublicKeyFile )
{
return
}
$PrivateKeyFile = Resolve-KeyPath -Path $PrivateKeyFile
if( -not $PrivateKeyFile )
{
return
}
if( (Test-Path -Path $PrivateKeyFile -PathType Leaf) )
{
if( -not $Force )
{
Write-Error ('Private key file ''{0}'' exists. Use the -Force switch to overwrite.' -f $PrivateKeyFile)
return
}
}
$tempDir = '{0}-{1}' -f (Split-Path -Leaf -Path $PSCommandPath),([IO.Path]::GetRandomFileName())
$tempDir = Join-Path -Path $env:TEMP -ChildPath $tempDir
New-Item -Path $tempDir -ItemType 'Directory' | Out-Null
$tempInfFile = Join-Path -Path $tempDir -ChildPath 'temp.inf'
try
{
$certReqPath = Get-Command -Name 'certreq.exe' | Select-Object -ExpandProperty 'Path'
if( -not $certReqPath )
{
return
}
# Taken from example 1 of the Protect-CmsMessage help topic.
[int]$daysValid = [Math]::Floor(($ValidTo - $ValidFrom).TotalDays)
[int]$MaxDaysValid = [Math]::Floor(([DateTime]::MaxValue - [DateTime]::UtcNow).TotalDays)
Write-Debug -Message ('Days Valid: {0}' -f $daysValid)
Write-Debug -Message ('Max Days Valid: {0}' -f $MaxDaysValid)
if( $daysValid -gt $MaxDaysValid )
{
Write-Debug -Message ('Adjusted Days Valid: {0}' -f $daysValid)
$daysValid = $MaxDaysValid
}
(@'
[Version]
Signature = "$Windows NT$"
[Strings]
szOID_ENHANCED_KEY_USAGE = "2.5.29.37"
szOID_DOCUMENT_ENCRYPTION = "1.3.6.1.4.1.311.80.1"
[NewRequest]
Subject = "{0}"
MachineKeySet = false
KeyLength = {1}
KeySpec = AT_KEYEXCHANGE
HashAlgorithm = {2}
Exportable = true
RequestType = Cert
KeyUsage = "CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE"
ValidityPeriod = Days
ValidityPeriodUnits = {3}
[Extensions]
%szOID_ENHANCED_KEY_USAGE% = "{{text}}%szOID_DOCUMENT_ENCRYPTION%"
'@ -f $Subject,$Length,$Algorithm,$daysValid) | Set-Content -Path $tempInfFile
Get-Content -Raw -Path $tempInfFile | Write-Debug
$output = & $certReqPath -q -new $tempInfFile $PublicKeyFile
if( $LASTEXITCODE -or -not (Test-Path -Path $PublicKeyFile -PathType Leaf) )
{
Write-Error ('Failed to create public/private key pair:{0}{1}' -f ([Environment]::NewLine),($output -join ([Environment]::NewLine)))
return
}
else
{
$output | Write-Debug
}
$publicKey = Get-Certificate -Path $PublicKeyFile
if( -not $publicKey )
{
Write-Error ('Failed to load public key ''{0}'':{1}{2}' -f $PublicKeyFile,([Environment]::NewLine),($output -join ([Environment]::NewLine)))
return
}
$privateCertPath = Join-Path -Path 'cert:\CurrentUser\My' -ChildPath $publicKey.Thumbprint
if( -not (Test-Path -Path $privateCertPath -PathType Leaf) )
{
Write-Error -Message ('Private key ''{0}'' not found. Did certreq.exe fail to install the private key there?' -f $privateCertPath)
return
}
try
{
$privateCert = Get-Item -Path $privateCertPath
if( -not $privateCert.HasPrivateKey )
{
Write-Error -Message ('Certificate ''{0}'' doesn''t have a private key.' -f $privateCertPath)
return
}
if( -not $PSBoundParameters.ContainsKey('Password') )
{
$Password = Read-Host -Prompt 'Enter private key password' -AsSecureString
}
$privateCertBytes = $privateCert.Export( 'PFX', $Password )
[IO.File]::WriteAllBytes( $PrivateKeyFile, $privateCertBytes )
Get-Item $PublicKeyFile
Get-Item $PrivateKeyFile
}
finally
{
Remove-Item -Path $privateCertPath
}
}
finally
{
Remove-Item -Path $tempDir -Recurse
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function New-TempDirectory
{
<#
.SYNOPSIS
Creates a new temporary directory with a random name.
.DESCRIPTION
A new temporary directory is created in the current user's `env:TEMP` directory. The directory's name is created using the `Path` class's [GetRandomFileName method](http://msdn.microsoft.com/en-us/library/system.io.path.getrandomfilename.aspx).
To add a custom prefix to the directory name, use the `Prefix` parameter. If you pass in a path, only its name will be used. In this way, you can pass `$MyInvocation.MyCommand.Definition` (PowerShell 2) or `$PSCommandPath` (PowerShell 3+), which will help you identify what scripts are leaving cruft around in the temp directory.
Added `-WhatIf` support in Carbon 2.0.
.LINK
http://msdn.microsoft.com/en-us/library/system.io.path.getrandomfilename.aspx
.EXAMPLE
New-TempDirectory
Demonstrates how to create a new temporary directory, e.g. `C:\Users\ajensen\AppData\Local\Temp\5pobd3tu.5rn`.
.EXAMPLE
New-TempDirectory -Prefix 'Carbon'
Demonstrates how to create a new temporary directory with a custom prefix for its name, e.g. `C:\Users\ajensen\AppData\Local\Temp\Carbon5pobd3tu.5rn`.
.EXAMPLE
New-TempDirectory -Prefix $MyInvocation.MyCommand.Definition
Demonstrates how you can use `$MyInvocation.MyCommand.Definition` in PowerShell 2 to create a new, temporary directory, named after the currently executing scripts, e.g. `C:\Users\ajensen\AppData\Local\Temp\New-TempDirectory.ps15pobd3tu.5rn`.
.EXAMPLE
New-TempDirectory -Prefix $PSCommandPath
Demonstrates how you can use `$PSCommandPath` in PowerShell 3+ to create a new, temporary directory, named after the currently executing scripts, e.g. `C:\Users\ajensen\AppData\Local\Temp\New-TempDirectory.ps15pobd3tu.5rn`.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
[OutputType([IO.DirectoryInfo])]
param(
[string]
# A prefix to use, so you can more easily identify *what* created the temporary directory. If you pass in a path, it will be converted to a file name.
$Prefix
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$tempDir = [IO.Path]::GetRandomFileName()
if( $Prefix )
{
$Prefix = Split-Path -Leaf -Path $Prefix
$tempDir = '{0}{1}' -f $Prefix,$tempDir
}
$tempDir = Join-Path -Path $env:TEMP -ChildPath $tempDir
New-Item -Path $tempDir -ItemType 'Directory' -Verbose:$VerbosePreference
}
Set-Alias -Name 'New-TempDir' -Value 'New-TempDirectory'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Protect-Acl
{
<#
.SYNOPSIS
Protects an ACL so that changes to its parent can't be inherited to it.
.DESCRIPTION
New items in the registry or file system will usually inherit ACLs from its parent. This function stops an item from inheriting rules from its, and will optionally preserve the existing inherited rules. Any existing, non-inherited access rules are left in place.
.LINK
Grant-Permission
.EXAMPLE
Protect-Acl -Path C:\Projects\Carbon
Removes all inherited access rules from the `C:\Projects\Carbon` directory. Non-inherited rules are preserved.
.EXAMPLE
Protect-Acl -Path hklm:\Software\Carbon -Preserve
Stops `HKLM:\Software\Carbon` from inheriting acces rules from its parent, but preserves the existing, inheritied access rules.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string]
# The file system or registry path whose
$Path,
[Switch]
# Keep the inherited access rules on this item.
$Preserve
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Write-Verbose "Removing access rule inheritance on '$Path'."
$acl = Get-Acl -Path $Path
$acl.SetAccessRuleProtection( $true, $Preserve )
$acl | Set-Acl -Path $Path
}
Set-Alias -Name Unprotect-AclAccessRules -Value Protect-Acl
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
filter Protect-String
{
<#
.SYNOPSIS
Encrypts a string.
.DESCRIPTION
Strings can be encrypted with the Data Protection API (DPAPI) or RSA.
## DPAPI
The DPAPI hides the encryptiong/decryption keys from you. As such, anything encrpted with via DPAPI can only be decrypted on the same computer it was encrypted on. Use the `ForUser` switch so that only the user who encrypted can decrypt. Use the `ForComputer` switch so that any user who can log into the computer can decrypt. To encrypt as a specific user on the local computer, pass that user's credentials with the `Credential` parameter. (Note this method doesn't work over PowerShell remoting.)
## RSA
RSA is an assymetric encryption/decryption algorithm, which requires a public/private key pair. The secret is encrypted with the public key, and can only be decrypted with the corresponding private key. The secret being encrypted can't be larger than the RSA key pair's size/length, usually 1024, 2048, or 4096 bits (128, 256, and 512 bytes, respectively).
You can specify the public key in three ways:
* with a `System.Security.Cryptography.X509Certificates.X509Certificate2` object, via the `Certificate` parameter
* with a certificate in one of the Windows certificate stores, passing its unique thumbprint via the `Thumbprint` parameter, or via the `PublicKeyPath` parameter cn be certificat provider path, e.g. it starts with `cert:\`.
* with a X509 certificate file, via the `PublicKeyPath` parameter
.LINK
New-RsaKeyPair
.LINK
Unprotect-String
.LINK
http://msdn.microsoft.com/en-us/library/system.security.cryptography.protecteddata.aspx
.EXAMPLE
Protect-String -String 'TheStringIWantToEncrypt' -ForUser | Out-File MySecret.txt
Encrypts the given string and saves the encrypted string into MySecret.txt. Only the user who encrypts the string can unencrypt it.
.EXAMPLE
$cipherText = Protect-String -String "MySuperSecretIdentity" -ForComputer
Encrypts the given string and stores the value in $cipherText. Because the encryption scope is set to LocalMachine, any user logged onto the local computer can decrypt `$cipherText`.
.EXAMPLE
Protect-String -String 's0000p33333r s33333cr33333t' -Credential (Get-Credential 'builduser')
Demonstrates how to use `Protect-String` to encrypt a secret as a specific user. This is useful for situation where a secret needs to be encrypted by a user other than the user running `Protect-String`. Encrypting as a specific user won't work over PowerShell remoting.
.EXAMPLE
Protect-String -String 'the secret sauce' -Certificate $myCert
Demonstrates how to encrypt a secret using RSA with a `System.Security.Cryptography.X509Certificates.X509Certificate2` object. You're responsible for creating/loading it. The `New-RsaKeyPair` function will create a key pair for you, if you've got a Windows SDK installed.
.EXAMPLE
Protect-String -String 'the secret sauce' -Thumbprint '44A7C27F3353BC53F82318C14490D7E2500B6D9E'
Demonstrates how to encrypt a secret using RSA with a certificate in one of the Windows certificate stores. All local machine and user stores are searched.
.EXAMPLE
ProtectString -String 'the secret sauce' -PublicKeyPath 'C:\Projects\Security\publickey.cer'
Demonstrates how to encrypt a secret using RSA with a certificate file. The file must be loadable by the `System.Security.Cryptography.X509Certificates.X509Certificate` class.
.EXAMPLE
ProtectString -String 'the secret sauce' -PublicKeyPath 'cert:\LocalMachine\My\44A7C27F3353BC53F82318C14490D7E2500B6D9E'
Demonstrates how to encrypt a secret using RSA with a certificate in the store, giving its exact path.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position=0, ValueFromPipeline = $true)]
[string]
# The text to encrypt.
$String,
[Parameter(Mandatory=$true,ParameterSetName='DPAPICurrentUser')]
# Encrypts for the current user so that only he can decrypt.
[Switch]
$ForUser,
[Parameter(Mandatory=$true,ParameterSetName='DPAPILocalMachine')]
# Encrypts for the current computer so that any user logged into the computer can decrypt.
[Switch]
$ForComputer,
[Parameter(Mandatory=$true,ParameterSetName='DPAPIForUser')]
[Management.Automation.PSCredential]
# Encrypts for a specific user.
$Credential,
[Parameter(Mandatory=$true,ParameterSetName='RSAByCertificate')]
[Security.Cryptography.X509Certificates.X509Certificate2]
# The public key to use for encrypting.
$Certificate,
[Parameter(Mandatory=$true,ParameterSetName='RSAByThumbprint')]
[string]
# The thumbprint of the certificate, found in one of the Windows certificate stores, to use when encrypting. All certificate stores are searched.
$Thumbprint,
[Parameter(Mandatory=$true,ParameterSetName='RSAByPath')]
[string]
# The path to the public key to use for encrypting. Must be to an `X509Certificate2` object.
$PublicKeyPath,
[Parameter(ParameterSetName='RSAByCertificate')]
[Parameter(ParameterSetName='RSAByThumbprint')]
[Parameter(ParameterSetName='RSAByPath')]
[Switch]
# If true, uses Direct Encryption (PKCS#1 v1.5) padding. Otherwise (the default), uses OAEP (PKCS#1 v2) padding. See [Encrypt](http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.encrypt(v=vs.110).aspx) for information.
$UseDirectEncryptionPadding
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$stringBytes = [Text.Encoding]::UTF8.GetBytes( $String )
if( $PSCmdlet.ParameterSetName -like 'DPAPI*' )
{
if( $PSCmdlet.ParameterSetName -eq 'DPAPIForUser' )
{
$outFile = '{0}-{1}-stdout' -f (Split-Path -Leaf -Path $PSCommandPath),([IO.Path]::GetRandomFileName())
$outFile = Join-Path -Path $env:TEMP -ChildPath $outFile
Write-Verbose $outFile
'' | Set-Content -Path $outFile
$errFile = '{0}-{1}-stderr' -f (Split-Path -Leaf -Path $PSCommandPath),([IO.Path]::GetRandomFileName())
$errFile = Join-Path -Path $env:TEMP -ChildPath $errFile
Write-Verbose $errFile
'' | Set-Content -Path $errFile
try
{
$protectStringPath = Join-Path -Path $CarbonBinDir -ChildPath 'Protect-String.ps1' -Resolve
$encodedString = Protect-String -String $String -ForComputer
$p = Start-Process -FilePath "powershell.exe" `
-ArgumentList ('-NonInteractive -ExecutionPolicy ByPass -File "{0}" -ProtectedString {1}' -f $protectStringPath,$encodedString) `
-Credential $Credential `
-RedirectStandardOutput $outFile `
-RedirectStandardError $errFile `
-Wait `
-WindowStyle Hidden `
-PassThru
$p.WaitForExit()
$stdOut = Get-Content -Path $outFile -Raw
if( $stdOut )
{
Write-Verbose -Message $stdOut
}
$stdErr = Get-Content -Path $errFile -Raw
if( $stdErr )
{
Write-Error -Message $stdErr
return
}
if( $p.ExitCode -ne 0 )
{
Write-Error -Message ('Unknown error encrypting string as {0}: exit code {1}{2}{3}' -f $Credential.UserName,$p.ExitCode,([Environment]::NewLine),$stdOut)
return
}
if( $stdOut )
{
return Get-Content -Path $outFile -TotalCount 1
}
}
finally
{
Remove-Item -Path $outFile,$errFile -ErrorAction SilentlyContinue
}
}
else
{
$scope = [Security.Cryptography.DataProtectionScope]::CurrentUser
if( $PSCmdlet.ParameterSetName -eq 'DPAPILocalMachine' )
{
$scope = [Security.Cryptography.DataProtectionScope]::LocalMachine
}
$encryptedBytes = [Security.Cryptography.ProtectedData]::Protect( $stringBytes, $null, $scope )
}
}
elseif( $PSCmdlet.ParameterSetName -like 'RSA*' )
{
if( $PSCmdlet.ParameterSetName -eq 'RSAByThumbprint' )
{
$Certificate = Get-ChildItem -Path ('cert:\*\*\{0}' -f $Thumbprint) -Recurse | Select-Object -First 1
if( -not $Certificate )
{
Write-Error ('Certificate with thumbprint ''{0}'' not found.' -f $Thumbprint)
return
}
}
elseif( $PSCmdlet.ParameterSetName -eq 'RSAByPath' )
{
$Certificate = Get-Certificate -Path $PublicKeyPath
if( -not $Certificate )
{
return
}
}
$key = $Certificate.PublicKey.Key
if( $key -isnot ([Security.Cryptography.RSACryptoServiceProvider]) )
{
Write-Error ('Certificate ''{0}'' (''{1}'') is not an RSA key. Found a public key of type ''{2}'', but expected type ''{3}''.' -f $Certificate.Subject,$Certificate.Thumbprint,$key.GetType().FullName,[Security.Cryptography.RSACryptoServiceProvider].FullName)
return
}
try
{
$encryptedBytes = $key.Encrypt( $stringBytes, (-not $UseDirectEncryptionPadding) )
}
catch
{
if( $_.Exception.Message -match 'Bad Length\.' -or $_.Exception.Message -match 'The parameter is incorrect\.')
{
[int]$maxLengthGuess = ($key.KeySize - (2 * 160 - 2)) / 8
Write-Error -Message ('Failed to encrypt. String is longer than maximum length allowed by RSA and your key size, which is {0} bits. We estimate the maximum string size you can encrypt with certificate ''{1}'' ({2}) is {3} bytes. You may still get errors when you attempt to decrypt a string within a few bytes of this estimated maximum.' -f $key.KeySize,$Certificate.Subject,$Certificate.Thumbprint,$maxLengthGuess)
return
}
else
{
Write-Error -Exception $_.Exception
return
}
}
}
return [Convert]::ToBase64String( $encryptedBytes )
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Read-File
{
<#
.SYNOPSIS
Reads the contents of a text file, retrying if the read fails.
.DESCRIPTION
The `Read-File` function reads the contents of a text file, and will retry if the read fails. Use this function if you need to read files that can be intermittently locked, like the Windows hosts file. The file is returned line-by-line. Use the `Raw` switch to return the entrie file as a single string.
By default, it will retry 30 times, waiting 100 milliseconds between each try. YOu can control the number of retries and the wait between retries with the `MaximumTries` and `RetryDelayMilliseconds` parameters.
All errors raised while trying to read the file are ignored, except the error raised on the last try.
This function was introduced in Carbon 2.2.0.
.EXAMPLE
Read-File -Path 'C:\Path\to\my\file'
Demonstrates how to read each line from a text file.
.EXAMPLE
Read-File -Path 'C:\Path\to\my\file' -Raw
Demonstrates how to read the entire contents of a text file into a single string.
.EXAMPLE
Read-File -Path 'C:\Path\to\my\file' -MaximumRetries 10 -RetryDelayMilliseconds 1000
Demonstrates how to control how long to retry reading the text file. In this case, `Read-File` will try 10 times, waiting one second between tries.
.EXAMPLE
Read-File -Path 'C:\Path\to\my\file' -ErrorVariable 'readErrors'
Demonstrates how to check if the read failed. In this case, errors are copied to a 'readErrors' variable, so you would check if this error variable has any items.
#>
[CmdletBinding()]
[OutputType([string])]
param(
[Parameter(Mandatory=$true)]
# The path to the file to read.
$Path,
# The number of tries before giving up reading the file. The default is 30.
[int]
$MaximumTries = 30,
# The number of milliseconds to wait between tries. Default is 100 milliseconds.
[int]
$RetryDelayMilliseconds = 100,
[Switch]
# Return the file as one string. Otherwise, by default, the file is returned line-by-line.
$Raw
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$Path = Resolve-Path -Path $Path
if( -not $Path )
{
return
}
$tryNum = 1
$output = @()
do
{
$lastTry = $tryNum -eq $MaximumTries
if( $lastTry )
{
$errorAction = @{}
}
$numErrorsAtStart = $Global:Error.Count
try
{
if( $Raw )
{
$output = [IO.File]::ReadAllText($Path)
}
else
{
$output = Get-Content -Path $Path -ErrorAction SilentlyContinue -ErrorVariable 'cmdErrors'
if( $cmdErrors -and $lastTry )
{
foreach( $item in $cmdErrors )
{
$Global:Error.RemoveAt(0)
}
$cmdErrors | Write-Error
}
}
}
catch
{
if( $lastTry )
{
Write-Error -ErrorRecord $_
}
}
$numErrors = $Global:Error.Count - $numErrorsAtStart
if( -not $lastTry )
{
for( $idx = 0; $idx -lt $numErrors; ++$idx )
{
$Global:Error[0] | Out-String | Write-Debug
$Global:Error.RemoveAt(0)
}
}
if( $numErrors )
{
if( -not $lastTry )
{
Write-Debug -Message ('Failed to read file ''{0}'' (attempt #{1}). Retrying in {2} milliseconds.' -f $Path,$tryNum,$RetryDelayMilliseconds)
Start-Sleep -Milliseconds $RetryDelayMilliseconds
}
}
else
{
return $output
}
}
while( $tryNum++ -lt $MaximumTries )
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Remove-DotNetAppSetting
{
<#
.SYNOPSIS
Remove an app setting from the .NET machine.config file.
.DESCRIPTION
The `Remove-DotNetAppSetting` removes an app setting from one or more of the .NET machine.config file. The app setting can be removed from up to four different machine.config files:
* .NET 2.0 32-bit (switches -Clr2 -Framework)
* .NET 2.0 64-bit (switches -Clr2 -Framework64)
* .NET 4.0 32-bit (switches -Clr4 -Framework)
* .NET 4.0 64-bit (switches -Clr4 -Framework64)
Any combination of Framework and Clr switch can be used, but you MUST supply one of each.
If the app setting doesn't exist in the machine.config, nothing happens.
`Remove-DotNetAppSetting` was added in Carbon 2.2.0.
.LINK
Set-DotNetAppSetting
.LINK
Set-DotNetConnectionString
.EXAMPLE
> Remove-DotNetAppSetting -Name ExampleUrl -Framework -Framework64 -Clr2 -Clr4
Remvoes the `ExampleUrl` app setting from the following machine.config files:
* `%SYSTEMROOT%\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config`
* `%SYSTEMROOT%\Microsoft.NET\Framework64\v2.0.50727\CONFIG\machine.config`
* `%SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319\CONFIG\machine.config`
* `%SYSTEMROOT%\Microsoft.NET\Framework64\v4.0.30319\CONFIG\machine.config`
.EXAMPLE
> Remove-DotNetAppSetting -Name ExampleUrl -Framework64 -Clr4
Sets the ExampleUrl app setting in the following machine.config file:
* `%SYSTEMROOT%\Microsoft.NET\Framework64\v4.0.30319\CONFIG\machine.config`
#>
[CmdletBinding(SupportsShouldProcess=$true, DefaultParameterSetName='All')]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the app setting to remove.
$Name,
[Switch]
# Remove the app setting from a 32-bit machine.config. Must be used with one or both of the `Clr2` and `Clr4` switches to control which machine.config files to operate on.
$Framework,
[Switch]
# Remove the app setting from a 64-bit machine.config. Ignored if running on a 32-bit operating system. Must be used with one or both of the `Clr2` and `Clr4` switches to control which machine.config files to operate on.
$Framework64,
[Switch]
# Remove the app setting from a .NET 2.0 machine.config. Must be used with one or both of the `Framework` and `Framework64` switches to control which machine.config files to operate on.
$Clr2,
[Switch]
# Remove the app setting from a .NET 4.0 machine.config. Must be used with one or both of the `Framework` and `Framework64` switches to control which machine.config files to operate on.
$Clr4
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not ($Framework -or $Framework64) )
{
Write-Error "You must supply either or both of the Framework and Framework64 switches."
return
}
if( -not ($Clr2 -or $Clr4) )
{
Write-Error "You must supply either or both of the Clr2 and Clr4 switches."
return
}
$runtimes = @()
if( $Clr2 )
{
$runtimes += 'v2.0'
}
if( $Clr4 )
{
$runtimes += 'v4.0'
}
$runtimes | ForEach-Object {
$params = @{
FilePath = (Join-Path $CarbonBinDir 'Remove-DotNetAppSetting.ps1' -Resolve);
ArgumentList = @(
(ConvertTo-Base64 -Value $Name)
);
Runtime = $_;
ExecutionPolicy = [Microsoft.PowerShell.ExecutionPolicy]::RemoteSigned;
}
if( $Framework )
{
Invoke-PowerShell @params -x86
}
if( $Framework64 )
{
Invoke-PowerShell @params
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Remove-EnvironmentVariable
{
<#
.SYNOPSIS
Removes an environment variable.
.DESCRIPTION
Uses the .NET [Environment class](http://msdn.microsoft.com/en-us/library/z8te35sa) to remove an environment variable from the Process, User, or Computer scopes.
Changes to environment variables in the User and Machine scope are not picked up by running processes. Any running processes that use this environment variable should be restarted.
.LINK
Carbon_EnvironmentVariable
.LINK
Set-EnvironmentVariable
.LINK
http://msdn.microsoft.com/en-us/library/z8te35sa
.EXAMPLE
Remove-EnvironmentVariable -Name 'MyEnvironmentVariable' -ForProcess
Removes the `MyEnvironmentVariable` from the process scope.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The environment variable to remove.
$Name,
[Parameter(Mandatory=$true,ParameterSetName='ForProcess')]
# Removes the environment variable for the current process.
[Switch]
$ForProcess,
[Parameter(Mandatory=$true,ParameterSetName='ForUser')]
# Removes the environment variable for the current user.
[Switch]
$ForUser,
[Parameter(Mandatory=$true,ParameterSetName='ForMachine')]
# Removes the environment variable for the current computer.
[Switch]
$ForComputer
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$scope = $pscmdlet.ParameterSetName -replace '^For',''
if( $pscmdlet.ShouldProcess( "$scope-level environment variable '$Name'", "remove" ) )
{
[Environment]::SetEnvironmentVariable( $Name, $null, $scope )
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Remove-GroupMember
{
<#
.SYNOPSIS
Removes users or groups from a *local* group.
.DESCRIPTION
You would think it's pretty easy and straight-forward to remove users/groups from a local group, but you would be wrong. The quick solution is to use `net localgroup`, but that won't accept user/group names longer than 24 characters. This means you have to use the .NET Directory Services APIs. How do you reliably remove both users *and* groups? What if those users are in a domain? What if they're in another domain? What about built-in users? Fortunately, your brain hasn't exploded.
So, this function removes users or groups from a *local* group.
If the user or group is not a member, nothing happens.
`Remove-GroupMember` is new in Carbon 2.0.
.EXAMPLE
Remove-GroupMember -Name Administrators -Member EMPIRE\DarthVader,EMPIRE\EmperorPalpatine,REBELS\LSkywalker
Removes Darth Vader, Emperor Palpatine and Luke Skywalker from the local administrators group.
.EXAMPLE
Remove-GroupMember -Name TieFighters -Member NetworkService
Removes the local NetworkService account from the local TieFighters group.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The group name.
$Name,
[Parameter(Mandatory=$true)]
[string[]]
# The users/groups to remove from a group.
[Alias('Members')]
$Member
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
[DirectoryServices.AccountManagement.GroupPrincipal]$group = Get-Group -Name $Name
if( -not $group )
{
return
}
try
{
foreach( $_member in $Member )
{
$identity = Resolve-Identity -Name $_member
if( -not $identity )
{
continue
}
if( -not (Test-GroupMember -GroupName $group.Name -Member $_member) )
{
continue
}
Write-Verbose -Message ('[{0}] Members {1} ->' -f $Name,$identity.FullName)
if( -not $PSCmdlet.ShouldProcess(('removing ''{0}'' from local group ''{1}''' -f $identity.FullName, $group.Name), $null, $null) )
{
continue
}
try
{
$identity.RemoveFromLocalGroup( $group.Name )
}
catch
{
Write-Error ('Failed to remove ''{0}'' from local group ''{1}'': {2}.' -f $identity,$group.Name,$_)
}
}
}
finally
{
$group.Dispose()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Remove-HostsEntry
{
<#
.SYNOPSIS
Removes entries from the hosts file by hostname.
.DESCRIPTION
You can remove multiple entries or pipe entries into this function.
.EXAMPLE
Remove-HostsEntry -HostName 'adadvisor.net'
Demonstrates how to remove hosts entry for `adadvisor.net`, which you probably don't want to do.
.EXAMPLE
Remove-HostsEntry -HostName 'adadvisor.net','www.adchimp.com'
Demonstrates how to remove multiple hosts entries.
.EXAMPLE
('adadvisor.net','www.adchimp.com') | Remove-HostsEntry
Demonstrates how to pipe hostnames into `Remove-HostsEntry`.
.EXAMPLE
Remove-HostsEntry -HostName 'adadvisor.net' -Path 'C:\Projects\Carbon\adblockhosts'
Demonstrates how to work with a file other than Windows' default hosts file.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)]
[string[]]
# The hostname of the hosts entry/entries to remove.
$HostName,
[string]
# The hosts file to modify. Defaults to the Windows hosts file.
$Path = (Get-PathToHostsFile)
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$allHostNames = New-Object 'Collections.ArrayList'
}
process
{
$HostName |
ForEach-Object { [Text.RegularExpressions.Regex]::Escape( $_ ) } |
ForEach-Object { [void] $allHostNames.Add( $_ ) }
}
end
{
$regex = $allHostNames -join '|'
$regex = '^[0-9a-f.:]+\s+\b({0})\b.*$' -f $regex
$cmdErrors = @()
$newHostsFile = Read-File -Path $Path -ErrorVariable 'cmdErrors' |
Where-Object { $_ -notmatch $regex }
if( $cmdErrors )
{
return
}
$entryNoun = 'entry'
if( $HostName.Count -gt 1 )
{
$entryNoun = 'entries'
}
if( $PSCmdlet.ShouldProcess( $Path, ('removing hosts {0} {1}' -f $entryNoun,($HostName -join ', ')) ) )
{
$newHostsFile | Write-File -Path $Path
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Remove-IisMimeMap
{
<#
.SYNOPSIS
Removes a file extension to MIME type map from an entire web server.
.DESCRIPTION
IIS won't serve static files unless they have an entry in the MIME map. Use this function toremvoe an existing MIME map entry. If one doesn't exist, nothing happens. Not even an error.
If a specific website has the file extension in its MIME map, that site will continue to serve files with those extensions.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
Get-IisMimeMap
.LINK
Set-IisMimeMap
.EXAMPLE
Remove-IisMimeMap -FileExtension '.m4v' -MimeType 'video/x-m4v'
Removes the `.m4v` file extension so that IIS will no longer serve those files.
#>
[CmdletBinding(DefaultParameterSetName='ForWebServer')]
param(
[Parameter(Mandatory=$true,ParameterSetName='ForWebsite')]
[string]
# The name of the website whose MIME type to set.
$SiteName,
[Parameter(ParameterSetName='ForWebsite')]
[string]
# The optional site path whose configuration should be returned.
$VirtualPath = '',
[Parameter(Mandatory=$true)]
[string]
# The file extension whose MIME map to remove.
$FileExtension
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$getIisConfigSectionParams = @{ }
if( $PSCmdlet.ParameterSetName -eq 'ForWebsite' )
{
$getIisConfigSectionParams['SiteName'] = $SiteName
$getIisConfigSectionParams['VirtualPath'] = $VirtualPath
}
$staticContent = Get-IisConfigurationSection -SectionPath 'system.webServer/staticContent' @getIisConfigSectionParams
$mimeMapCollection = $staticContent.GetCollection()
$mimeMapToRemove = $mimeMapCollection |
Where-Object { $_['fileExtension'] -eq $FileExtension }
if( -not $mimeMapToRemove )
{
Write-Verbose ('MIME map for file extension {0} not found.' -f $FileExtension)
return
}
$mimeMapCollection.Remove( $mimeMapToRemove )
$staticContent.CommitChanges()
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Remove-IniEntry
{
<#
.SYNOPSIS
Removes an entry/line/setting from an INI file.
.DESCRIPTION
A configuration file consists of sections, led by a `[section]` header and followed by `name = value` entries. This function removes an entry in an INI file. Something like this:
[ui]
username = Regina Spektor <[email protected]>
[extensions]
share =
extdiff =
Names are not allowed to contains the equal sign, `=`. Values can contain any character. The INI file is parsed using `Split-Ini`. [See its documentation for more examples.](Split-Ini.html)
If the entry doesn't exist, does nothing.
Be default, operates on the INI file case-insensitively. If your INI is case-sensitive, use the `-CaseSensitive` switch.
.LINK
Set-IniEntry
.LINK
Split-Ini
.EXAMPLE
Remove-IniEntry -Path C:\Projects\Carbon\StupidStupid.ini -Section rat -Name tails
Removes the `tails` item in the `[rat]` section of the `C:\Projects\Carbon\StupidStupid.ini` file.
.EXAMPLE
Remove-IniEntry -Path C:\Users\me\npmrc -Name 'prefix' -CaseSensitive
Demonstrates how to remove an INI entry in an INI file that is case-sensitive.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param
(
[Parameter(Mandatory=$true)]
[string]
# The path to the INI file.
$Path,
[Parameter(Mandatory=$true)]
[string]
# The name of the INI entry to remove.
$Name,
[string]
# The section of the INI where the entry should be set.
$Section,
[Switch]
# Removes INI entries in a case-sensitive manner.
$CaseSensitive
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$settings = @{ }
if( Test-Path $Path -PathType Leaf )
{
$settings = Split-Ini -Path $Path -AsHashtable -CaseSensitive:$CaseSensitive
}
else
{
Write-Error ('INI file {0} not found.' -f $Path)
return
}
$key = $Name
if( $Section )
{
$key = '{0}.{1}' -f $Section,$Name
}
if( $settings.ContainsKey( $key ) )
{
$lines = New-Object 'Collections.ArrayList'
Get-Content -Path $Path | ForEach-Object { [void] $lines.Add( $_ ) }
$null = $lines.RemoveAt( ($settings[$key].LineNumber - 1) )
if( $PSCmdlet.ShouldProcess( $Path, ('remove INI entry {0}' -f $key) ) )
{
if( $lines )
{
$lines | Set-Content -Path $Path
}
else
{
Clear-Content -Path $Path
}
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Remove-Junction
{
<#
.SYNOPSIS
Removes a junction.
.DESCRIPTION
`Remove-Junction` removes an existing junction.
In Carbon 2.1.1 and earlier, the `Path` paramater does not support wildcard characters, nor can it delete junctions that contained wildcards.
Carbon 2.2.0 added support for wildcards in the `Path` parameter. If using wildcards, if the wildcard pattern doesn't match any junctions, nothing is removed and you'll get no errors. If the `Path` parameter does not contain wildcards, `Path` must exist and must be a path to a junction.
Carbon 2.2.0 also added the `LiteralPath` parameter. Use it to delete junctions whose path contains wildcard characters.
.LINK
Install-Junction
.LINK
New-Junction
.LINK
Test-PathIsJunction
.LINK
Uninstall-Junction
.EXAMPLE
Remove-Junction -Path 'C:\I\Am\A\Junction'
Removes the `C:\I\Am\A\Junction` path.
.EXAMPLE
Remove-Junction -path 'C:\Temp\*'
Demonstrates how to use wildcards to delete multiple junctions in a directory. Nothing happens if the wildcard doesn't match any junctions.
.EXAMPLE
Remove-Junction -LiteralPath 'C:\Temp\ContainsWildcards[]'
Demonstrates how to use the `Literalpath` parameter to delete a junction that contains wildcard characters.
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='Path')]
param(
[Parameter(Mandatory=$true,Position=0,ParameterSetName='Path')]
[string]
# The path to the junction to remove.
#
# Wildcards are supported in Carbon 2.2.0 and later.
$Path,
[Parameter(Mandatory=$true,ParameterSetName='LiteralPath')]
[string]
# The literal path to the junction to remove. Use this parameter to remove junctions whose paths contain wildcard characters.
#
# This parameter was added in Carbon 2.2.0.
$LiteralPath
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSCmdlet.ParameterSetName -eq 'Path' )
{
if( [Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Path) )
{
Get-Item -Path $Path |
Where-Object { $_.PsIsContainer -and $_.IsJunction } |
ForEach-Object { Remove-Junction -Path $_.FullName }
}
else
{
Remove-Junction -LiteralPath $Path
}
return
}
if( -not (Test-Path -LiteralPath $LiteralPath) )
{
Write-Error ('Path ''{0}'' not found.' -f $LiteralPath)
return
}
if( (Test-Path -LiteralPath $LiteralPath -PathType Leaf) )
{
Write-Error ('Path ''{0}'' is a file, not a junction.' -f $LiteralPath)
return
}
if( Test-PathIsJunction -LiteralPath $LiteralPath )
{
$LiteralPath = Resolve-Path -LiteralPath $LiteralPath |
Select-Object -ExpandProperty ProviderPath
if( $PSCmdlet.ShouldProcess($LiteralPath, "remove junction") )
{
[Carbon.IO.JunctionPoint]::Delete( $LiteralPath )
}
}
else
{
Write-Error ("Path '{0}' is a directory, not a junction." -f $LiteralPath)
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Remove-RegistryKeyValue
{
<#
.SYNOPSIS
Removes a value from a registry key, if it exists.
.DESCRIPTION
If the given key doesn't exist, nothing happens.
.EXAMPLE
Remove-RegistryKeyValue -Path hklm:\Software\Carbon\Test -Name 'InstallPath'
Removes the `InstallPath` value from the `hklm:\Software\Carbon\Test` registry key.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to the registry key where the value should be removed.
$Path,
[Parameter(Mandatory=$true)]
[string]
# The name of the value to remove.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( (Test-RegistryKeyValue -Path $Path -Name $Name) )
{
if( $pscmdlet.ShouldProcess( ('Item: {0} Property: {1}' -f $Path,$Name), 'Remove Property' ) )
{
Remove-ItemProperty -Path $Path -Name $Name
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Remove-SslCertificateBinding
{
<#
.SYNOPSIS
Removes an SSL certificate binding.
.DESCRIPTION
Uses the netsh command line application to remove an SSL certificate binding for an IP/port combination. If the binding doesn't exist, nothing is changed.
.EXAMPLE
> Remove-SslCertificateBinding -IPAddress '45.72.89.57' -Port 443
Removes the SSL certificate bound to IP 45.72.89.57 on port 443.
.EXAMPLE
> Remove-SslCertificateBinding
Removes the default SSL certificate from port 443. The default certificate is bound to all IP addresses.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[IPAddress]
# The IP address whose binding to remove. Default is all IP addresses.
$IPAddress = '0.0.0.0',
[UInt16]
# The port of the binding to remove. Default is port 443.
$Port = 443
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-SslCertificateBinding -IPAddress $IPAddress -Port $Port) )
{
return
}
if( $IPAddress.AddressFamily -eq [Net.Sockets.AddressFamily]::InterNetworkV6 )
{
$ipPort = '[{0}]:{1}' -f $IPAddress,$Port
}
else
{
$ipPort = '{0}:{1}' -f $IPAddress,$Port
}
Invoke-ConsoleCommand -Target $ipPort `
-Action "removing SSL certificate binding" `
-ScriptBlock { netsh http delete sslcert ipPort=$ipPort }
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Reset-HostsFile
{
<#
.SYNOPSIS
Removes all custom host entries from this computer's hosts file.
.DESCRIPTION
Sometimes you want to start over. This method removes all hosts entries from your hosts file after the default localhost entry.
By default, the current computer's hosts file is reset. You can operate on a custom hosts file by passing its path to the `Path` argument.
.EXAMPLE
Reset-HostsFile
If your hosts file contains something like this:
127.0.0.1 localhost
10.1.2.3 myserver
10.5.6.7 myserver2
After calling `Reset-HostsFile`, your hosts will contain:
127.0.0.1 localhost
.EXAMPLE
Reset-HostsFile -Path my\custom\hosts
Resets the hosts file at `my\custom\hosts`.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[string]
# The path to the hosts file to modify. Defaults to the local computer's hosts file.
$Path = (Get-PathToHostsFile)
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if(-not (Test-Path $Path) )
{
Write-Warning "Creating hosts file '$Path'."
New-Item $Path -ItemType File
}
$cmdErrors = @()
[string[]]$lines = Read-File -Path $Path -ErrorVariable 'cmdErrors'
if( $cmdErrors )
{
return
}
$outLines = New-Object -TypeName 'System.Collections.ArrayList'
foreach($line in $lines)
{
if($line.Trim().StartsWith("#") -or ($line.Trim() -eq '') )
{
[void] $outlines.Add($line)
}
else
{
break
}
}
[void] $outlines.Add("127.0.0.1 localhost")
if( $PSCmdlet.ShouldProcess( $Path, "Reset-HostsFile" ) )
{
$outlines | Write-File -Path $Path
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Reset-MsmqQueueManagerID
{
<#
.SYNOPSIS
Resets the MSMQ Queue Manager ID.
.DESCRIPTION
Removes any existing MSMQ Queue Manager ID in the registry and restarts MSMQ so that it will generate a fresh QM ID.
Each instance of MSMQ should have its own unique Queue Manager ID. If multiple machines have the same Queue Manager ID, destination queues think messages are actually coming from the same computer, and messages are lost/dropped. If you clone new servers from a template or from old servers, you'll get duplicate Queue Manager IDs. This function causes MSMQ to reset its Queue Manager ID.
.EXAMPLE
Reset-MsmqQueueManagerId
.LINK
http://blogs.msdn.com/b/johnbreakwell/archive/2007/02/06/msmq-prefers-to-be-unique.aspx
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Write-Verbose "Resetting MSMQ Queue Manager ID."
Write-Verbose "Stopping MSMQ."
Stop-Service MSMQ -Force
$QMIdPath = "HKLM:\SOFTWARE\Microsoft\MSMQ\Parameters\MachineCache"
$QMIdName = "QMId"
$QMId = Get-RegistryKeyValue -Path $QMIdPath -Name $QMIdName
Write-Verbose "Existing QMId: $QMId"
Remove-RegistryKeyValue -Path $QMIdPath -Name $QMIdName
$MSMQSysPrepPath = "HKLM:\SOFTWARE\Microsoft\MSMQ\Parameters"
$MSMQSysPrepName = "SysPrep"
Remove-RegistryKeyValue -Path $MSMQSysPrepPath -Name $MSMQSysPrepName
Set-RegistryKeyValue -Path $MSMQSysPrepPath -Name $MSMQSysPrepName -DWord 1
Write-Verbose "Starting MSMQ"
Start-Service MSMQ
$QMId = Get-RegistryKeyValue -Path $QMIdPath -Name $QMIdName
Write-Verbose "New QMId: $QMId"
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Resolve-FullPath
{
<#
.SYNOPSIS
Converts a relative path to an absolute path.
.DESCRIPTION
Unlike `Resolve-Path`, this function does not check whether the path exists. It just converts relative paths to absolute paths.
Unrooted paths (e.g. `..\..\See\I\Do\Not\Have\A\Root`) are first joined with the current directory (as returned by `Get-Location`).
.EXAMPLE
Resolve-FullPath -Path 'C:\Projects\Carbon\Test\..\Carbon\FileSystem.ps1'
Returns `C:\Projects\Carbon\Carbon\FileSystem.ps1`.
.EXAMPLE
Resolve-FullPath -Path 'C:\Projects\Carbon\..\I\Do\Not\Exist'
Returns `C:\Projects\I\Do\Not\Exist`.
.EXAMPLE
Resolve-FullPath -Path ..\..\Foo\..\Bar
Because the `Path` isn't rooted, joins `Path` with the current directory (as returned by `Get-Location`), and returns the full path. If the current directory is `C:\Projects\Carbon`, returns `C:\Bar`.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to resolve. Must be rooted, i.e. have a drive at the beginning.
$Path
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not ( [System.IO.Path]::IsPathRooted($Path) ) )
{
$Path = Join-Path (Get-Location) $Path
}
return [IO.Path]::GetFullPath($Path)
}
Set-Alias -Name 'ConvertTo-FullPath' -Value 'Resolve-FullPath'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Resolve-Identity
{
<#
.SYNOPSIS
Gets domain, name, type, and SID information about a user or group.
.DESCRIPTION
The `Resolve-Identity` function takes an identity name or security identifier (SID) and gets its canonical representation. It returns a `Carbon.Identity` object, which contains the following information about the identity:
* Domain - the domain the user was found in
* FullName - the users full name, e.g. Domain\Name
* Name - the user's username or the group's name
* Type - the Sid type.
* Sid - the account's security identifier as a `System.Security.Principal.SecurityIdentifier` object.
The common name for an account is not always the canonical name used by the operating system. For example, the local Administrators group is actually called BUILTIN\Administrators. This function uses the `LookupAccountName` and `LookupAccountSid` Windows functions to resolve an account name or security identifier into its domain, name, full name, SID, and SID type.
You may pass a `System.Security.Principal.SecurityIdentifer`, a SID in SDDL form (as a string), or a SID in binary form (a byte array) as the value to the `SID` parameter. You'll get an error and nothing returned if the SDDL or byte array SID are invalid.
If the name or security identifier doesn't represent an actual user or group, an error is written and nothing is returned.
.LINK
Test-Identity
.LINK
Resolve-IdentityName
.LINK
http://msdn.microsoft.com/en-us/library/system.security.principal.securityidentifier.aspx
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/aa379601.aspx
.LINK
ConvertTo-SecurityIdentifier
.LINK
Resolve-IdentityName
.LINK
Test-Identity
.OUTPUTS
Carbon.Identity.
.EXAMPLE
Resolve-Identity -Name 'Administrators'
Returns an object representing the `Administrators` group.
.EXAMPLE
Resolve-Identity -SID 'S-1-5-21-2678556459-1010642102-471947008-1017'
Demonstrates how to use a SID in SDDL form to convert a SID into an identity.
.EXAMPLE
Resolve-Identity -SID (New-Object 'Security.Principal.SecurityIdentifier' 'S-1-5-21-2678556459-1010642102-471947008-1017')
Demonstrates that you can pass a `SecurityIdentifier` object as the value of the SID parameter.
.EXAMPLE
Resolve-Identity -SID $sidBytes
Demonstrates that you can use a byte array that represents a SID as the value of the `SID` parameter.
#>
[CmdletBinding(DefaultParameterSetName='ByName')]
[OutputType([Carbon.Identity])]
param(
[Parameter(Mandatory=$true,ParameterSetName='ByName',Position=0)]
[string]
# The name of the identity to return.
$Name,
[Parameter(Mandatory=$true,ParameterSetName='BySid')]
# The SID of the identity to return. Accepts a SID in SDDL form as a `string`, a `System.Security.Principal.SecurityIdentifier` object, or a SID in binary form as an array of bytes.
$SID
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSCmdlet.ParameterSetName -eq 'BySid' )
{
$SID = ConvertTo-SecurityIdentifier -SID $SID
if( -not $SID )
{
return
}
$id = [Carbon.Identity]::FindBySid( $SID )
if( -not $id )
{
Write-Error ('Identity ''{0}'' not found.' -f $SID) -ErrorAction $ErrorActionPreference
}
return $id
}
if( -not (Test-Identity -Name $Name) )
{
Write-Error ('Identity ''{0}'' not found.' -f $Name) -ErrorAction $ErrorActionPreference
return
}
return [Carbon.Identity]::FindByName( $Name )
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Resolve-IdentityName
{
<#
.SYNOPSIS
Determines the full, NT identity name for a user or group.
.DESCRIPTION
`Resolve-IdentityName` resolves a user/group name into its full, canonical name, used by the operating system. For example, the local Administrators group is actually called BUILTIN\Administrators. With a canonical username, you can unambiguously compare principals on objects that contain user/group information.
If unable to resolve a name into an identity, `Resolve-IdentityName` returns nothing.
If you want to get full identity information (domain, type, sid, etc.), use `Resolve-Identity`.
In Carbon 2.0, you can also resolve a SID into its identity name. The `SID` parameter accepts a SID in SDDL form as a `string`, a `System.Security.Principal.SecurityIdentifier` object, or a SID in binary form as an array of bytes. If the SID no longer maps to an active account, you'll get the original SID in SDDL form (as a string) returned to you.
.LINK
ConvertTo-SecurityIdentifier
.LINK
Resolve-Identity
.LINK
Test-Identity
.LINK
http://msdn.microsoft.com/en-us/library/system.security.principal.securityidentifier.aspx
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/aa379601.aspx
.OUTPUTS
string
.EXAMPLE
Resolve-IdentityName -Name 'Administrators'
Returns `BUILTIN\Administrators`, the canonical name for the local Administrators group.
#>
[CmdletBinding(DefaultParameterSetName='ByName')]
[OutputType([string])]
param(
[Parameter(Mandatory=$true,ParameterSetName='ByName',Position=0)]
[string]
# The name of the identity to return.
$Name,
[Parameter(Mandatory=$true,ParameterSetName='BySid')]
# Get an identity's name from its SID. Accepts a SID in SDDL form as a `string`, a `System.Security.Principal.SecurityIdentifier` object, or a SID in binary form as an array of bytes.
#
# This parameter is new in Carbon 2.0.
$SID
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSCmdlet.ParameterSetName -eq 'ByName' )
{
return Resolve-Identity -Name $Name -ErrorAction Ignore | Select-Object -ExpandProperty 'FullName'
}
elseif( $PSCmdlet.ParameterSetName -eq 'BySid' )
{
$SID = ConvertTo-SecurityIdentifier -SID $SID
if( -not $SID )
{
return
}
$id = [Carbon.Identity]::FindBySid( $SID )
if( $id )
{
return $id.FullName
}
else
{
return $SID.ToString()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Resolve-NetPath
{
<#
.SYNOPSIS
OBSOLETE. Will be removed in a future major version of Carbon.
.DESCRIPTION
OBSOLETE. Will be removed in a future major version of Carbon.
.EXAMPLE
Write-Error 'OBSOLETE. Will be removed in a future major version of Carbon.'
Demonstates that `Resolve-NetPath` is obsolete and you shouldn't use it.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Write-Warning ('Resolve-NetPath is obsolete and will be removed in a future major version of Carbon. Do not use.')
$netCmd = Get-Command -CommandType Application -Name net.exe* |
Where-Object { $_.Name -eq 'net.exe' }
if( $netCmd )
{
return $netCmd.Definition
}
$netPath = Join-Path $env:WINDIR system32\net.exe
if( (Test-Path -Path $netPath -PathType Leaf) )
{
return $netPath
}
Write-Error 'net.exe command not found.'
return $null
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Resolve-PathCase
{
<#
.SYNOPSIS
Returns the real, canonical case of a path.
.DESCRIPTION
The .NET and Windows path/file system APIs respect and preserve the case of paths passed to them. This function will return the actual case of a path on the file system, regardless of the case of the string passed in.
If the path doesn't an exist, an error is written and nothing is returned.
.EXAMPLE
Resolve-PathCase -Path "C:\WINDOWS\SYSTEM32"
Returns `C:\Windows\system32`.
.EXAMPLE
Resolve-PathCase -Path 'c:\projects\carbon'
Returns `C:\Projects\Carbon`.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[string]
# The path whose real, canonical case should be returned.
[Alias('FullName')]
$Path
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Path -Path $Path) )
{
Write-Error "Path '$Path' not found."
return
}
$uri = [uri]$Path
if( $uri.IsUnc )
{
Write-Error ('Path ''{0}'' is a UNC path, which is not supported.' -f $Path)
return
}
if( -not ([IO.Path]::IsPathRooted($Path)) )
{
$Path = (Resolve-Path -Path $Path).Path
}
$qualifier = '{0}\' -f (Split-Path -Qualifier -Path $Path)
$qualifier = Get-Item -Path $qualifier | Select-Object -ExpandProperty 'Name'
$canonicalPath = ''
do
{
$parent = Split-Path -Parent -Path $Path
$leaf = Split-Path -Leaf -Path $Path
$canonicalLeaf = Get-ChildItem -Path $parent -Filter $leaf
if( $canonicalPath )
{
$canonicalPath = Join-Path -Path $canonicalLeaf -ChildPath $canonicalPath
}
else
{
$canonicalPath = $canonicalLeaf
}
}
while( $parent -ne $qualifier -and ($Path = Split-Path -Parent -Path $Path) )
return Join-Path -Path $qualifier -ChildPath $canonicalPath
}
Set-Alias -Name 'Get-PathCanonicalCase' -Value 'Resolve-PathCase'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Resolve-RelativePath
{
<#
.SYNOPSIS
Converts a path to a relative path from a given source.
.DESCRIPTION
The .NET framework doesn't expose an API for getting a relative path to an item. This function uses Win32 APIs to call [PathRelativePathTo](http://msdn.microsoft.com/en-us/library/windows/desktop/bb773740.aspx).
Neither the `From` or `To` paths need to exist.
.EXAMPLE
Resolve-RelativePath -Path 'C:\Program Files' -FromDirectory 'C:\Windows\system32'
Returns `..\..\Program Files`.
.EXAMPLE
Get-ChildItem * | Resolve-RelativePath -FromDirectory 'C:\Windows\system32'
Returns the relative path from the `C:\Windows\system32` directory to the current directory.
.EXAMPLE
Resolve-RelativePath -Path 'C:\I\do\not\exist\either' -FromDirectory 'C:\I\do\not\exist'
Returns `.\either`.
.EXAMPLE
Resolve-RelativePath -Path 'C:\I\do\not\exist\either' -FromFile 'C:\I\do\not\exist_file'
Treats `C:\I\do\not\exist_file` as a file, so returns a relative path of `.\exist\either`.
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773740.aspx
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipelineByPropertyName=$true)]
[string]
# The path to convert to a relative path. It will be relative to the value of the From parameter.
[Alias('FullName')]
$Path,
[Parameter(Mandatory=$true,ParameterSetName='FromDirectory')]
[string]
# The source directory from which the relative path will be calculated. Can be a string or an file system object.
$FromDirectory,
[Parameter(Mandatory=$true,ParameterSetName='FromFile')]
[string]
# The source directory from which the relative path will be calculated. Can be a string or an file system object.
$FromFile
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
}
process
{
$relativePath = New-Object System.Text.StringBuilder 260
switch( $pscmdlet.ParameterSetName )
{
'FromFile'
{
$fromAttr = [IO.FileAttributes]::Normal
$fromPath = $FromFile
}
'FromDirectory'
{
$fromAttr = [IO.FileAttributes]::Directory
$fromPath = $FromDirectory
}
}
$toPath = $Path
if( $Path | Get-Member -Name 'FullName' )
{
$toPath = $Path.FullName
}
$toAttr = [IO.FileAttributes]::Normal
$converted = [Carbon.IO.Path]::PathRelativePathTo( $relativePath, $fromPath, $fromAttr, $toPath, $toAttr )
$result = if( $converted ) { $relativePath.ToString() } else { $null }
return $result
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Resolve-WindowsFeatureName
{
<#
.SYNOPSIS
INTERNAL. DO NOT USE. Converts a Carbon-specific, common Windows feature name, into the feature name used on the current computer.
.DESCRIPTION
Windows feature names change between versions. This function converts a Carbon-specific name into feature names used on the current computer's version of Windows.
**This function is not available on Windows 8/2012.**
.EXAMPLE
Resolve-WindowsFeatureNames -Name 'Iis','Msmq'
Returns `'IIS-WebServer','MSMQ-Server'` if running Windows 7/Windows 2008 R2, or `'Web-WebServer','MSMQ-Server'` if on Windows 2008.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string[]]
# The Carbon feature names to convert to Windows-specific feature names.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Write-Warning -Message ('Resolve-WindowsFeatureName is obsolete and will be removed in a future major version of Carbon.')
$featureMap = @{
Iis = 'Web-WebServer';
IisHttpRedirection = 'Web-Http-Redirect';
Msmq = 'MSMQ-Server';
MsmqHttpSupport = 'MSMQ-HTTP-Support';
MsmqActiveDirectoryIntegration = 'MSMQ-Directory';
}
if( $useOCSetup )
{
$featureMap = @{
Iis = 'IIS-WebServer';
IisHttpRedirection = 'IIS-HttpRedirect';
Msmq = 'MSMQ-Server';
MsmqHttpSupport = 'MSMQ-HTTP';
MsmqActiveDirectoryIntegration = 'MSMQ-ADIntegration';
}
}
$Name |
Where-Object { $featureMap.ContainsKey( $_ ) } |
ForEach-Object { $featureMap[$_] }
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Restart-RemoteService
{
<#
.SYNOPSIS
Restarts a service on a remote machine.
.DESCRIPTION
One of the annoying features of PowerShell is that the `Stop-Service`, `Start-Service` and `Restart-Service` cmdlets don't have `ComputerName` parameters to start/stop/restart a service on a remote computer. You have to use `Get-Service` to get the remote service:
$service = Get-Service -Name DeathStar -ComputerName Yavin
$service.Stop()
$service.Start()
# or (and no, you can't pipe the service directly to `Restart-Service`)
Get-Service -Name DeathStar -ComputerName Yavin |
ForEach-Object { Restart-Service -InputObject $_ }
This function does all this unnecessary work for you.
You'll get an error if you attempt to restart a non-existent service.
.EXAMPLE
Restart-RemoteService -Name DeathStar -ComputerName Yavin
Restarts the `DeathStar` service on Yavin. If the DeathStar service doesn't exist, you'll get an error.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The service name to restart.
$Name,
[Parameter(Mandatory=$true)]
[string]
# The name of the computer where the service lives.
$ComputerName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$service = Get-Service -Name $name -ComputerName $computerName
if($service)
{
if($pscmdlet.ShouldProcess( "$name on $computerName", "restart"))
{
$service.Stop()
$service.Start()
}
}
else
{
Write-Error "Unable to restart remote service because I could not get a reference to service $name on machine: $computerName"
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Revoke-Privilege
{
<#
.SYNOPSIS
Revokes an identity's privileges to perform system operations and certain types of logons.
.DESCRIPTION
Valid privileges are documented on Microsoft's website: [Privilege Constants](http://msdn.microsoft.com/en-us/library/windows/desktop/bb530716.aspx) and [Account Right Constants](http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671.aspx). Known values as of August 2014 are:
* SeAssignPrimaryTokenPrivilege
* SeAuditPrivilege
* SeBackupPrivilege
* SeBatchLogonRight
* SeChangeNotifyPrivilege
* SeCreateGlobalPrivilege
* SeCreatePagefilePrivilege
* SeCreatePermanentPrivilege
* SeCreateSymbolicLinkPrivilege
* SeCreateTokenPrivilege
* SeDebugPrivilege
* SeDenyBatchLogonRight
* SeDenyInteractiveLogonRight
* SeDenyNetworkLogonRight
* SeDenyRemoteInteractiveLogonRight
* SeDenyServiceLogonRight
* SeEnableDelegationPrivilege
* SeImpersonatePrivilege
* SeIncreaseBasePriorityPrivilege
* SeIncreaseQuotaPrivilege
* SeIncreaseWorkingSetPrivilege
* SeInteractiveLogonRight
* SeLoadDriverPrivilege
* SeLockMemoryPrivilege
* SeMachineAccountPrivilege
* SeManageVolumePrivilege
* SeNetworkLogonRight
* SeProfileSingleProcessPrivilege
* SeRelabelPrivilege
* SeRemoteInteractiveLogonRight
* SeRemoteShutdownPrivilege
* SeRestorePrivilege
* SeSecurityPrivilege
* SeServiceLogonRight
* SeShutdownPrivilege
* SeSyncAgentPrivilege
* SeSystemEnvironmentPrivilege
* SeSystemProfilePrivilege
* SeSystemtimePrivilege
* SeTakeOwnershipPrivilege
* SeTcbPrivilege
* SeTimeZonePrivilege
* SeTrustedCredManAccessPrivilege
* SeUndockPrivilege
* SeUnsolicitedInputPrivilege
.LINK
Carbon_Privilege
.LINK
Get-Privilege
.LINK
Grant-Privilege
.LINK
Test-Privilege
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/bb530716.aspx
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671.aspx
.EXAMPLE
Revoke-Privilege -Identity Batcomputer -Privilege SeServiceLogonRight
Revokes the Batcomputer account's ability to logon as a service. Don't restart that thing!
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The identity to grant a privilege.
$Identity,
[Parameter(Mandatory=$true)]
[string[]]
# The privileges to revoke.
$Privilege
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$account = Resolve-Identity -Name $Identity
if( -not $account )
{
return
}
# Convert the privileges from the user into their canonical names.
$cPrivileges = Get-Privilege -Identity $account.FullName |
Where-Object { $Privilege -contains $_ }
if( -not $cPrivileges )
{
return
}
try
{
[Carbon.Security.Privilege]::RevokePrivileges($account.FullName,$cPrivileges)
}
catch
{
Write-Error -Message ('Failed to revoke {0}''s {1} privilege(s).' -f $account.FullName,($cPrivileges -join ', '))
$ex = $_.Exception
while( $ex.InnerException )
{
$ex = $ex.InnerException
Write-Error -Exception $ex
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-CryptoKeySecurity
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Security.Cryptography.X509Certificates.X509Certificate2]
$Certificate,
[Parameter(Mandatory=$true)]
[Security.AccessControl.CryptoKeySecurity]
$CryptoKeySecurity,
[Parameter(Mandatory=$true)]
[string]
$Action
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$keyContainerInfo = $Certificate.PrivateKey.CspKeyContainerInfo
$cspParams = New-Object 'Security.Cryptography.CspParameters' ($keyContainerInfo.ProviderType, $keyContainerInfo.ProviderName, $keyContainerInfo.KeyContainerName)
$cspParams.Flags = [Security.Cryptography.CspProviderFlags]::UseExistingKey
$cspParams.KeyNumber = $keyContainerInfo.KeyNumber
if( (Split-Path -NoQualifier -Path $Certificate.PSPath) -like 'LocalMachine\*' )
{
$cspParams.Flags = $cspParams.Flags -bor [Security.Cryptography.CspProviderFlags]::UseMachineKeyStore
}
$cspParams.CryptoKeySecurity = $CryptoKeySecurity
try
{
# persist the rule change
if( $PSCmdlet.ShouldProcess( ('{0} ({1})' -f $Certificate.Subject,$Certificate.Thumbprint), $Action ) )
{
$null = New-Object 'Security.Cryptography.RSACryptoServiceProvider' ($cspParams)
}
}
catch
{
$actualException = $_.Exception
while( $actualException.InnerException )
{
$actualException = $actualException.InnerException
}
Write-Error ('Failed to {0} to ''{1}'' ({2}) certificate''s private key: {3}: {4}' -f $Action,$Certificate.Subject,$Certificate.Thumbprint,$actualException.GetType().FullName,$actualException.Message)
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-DotNetAppSetting
{
<#
.SYNOPSIS
Sets an app setting in the .NET machine.config file.
.DESCRIPTION
The app setting can be set in up to four different machine.config files:
* .NET 2.0 32-bit (switches -Clr2 -Framework)
* .NET 2.0 64-bit (switches -Clr2 -Framework64)
* .NET 4.0 32-bit (switches -Clr4 -Framework)
* .NET 4.0 64-bit (switches -Clr4 -Framework64)
Any combination of Framework and Clr switch can be used, but you MUST supply one of each.
.EXAMPLE
> Set-DotNetAppSetting -Name ExampleUrl -Value example.com -Framework -Framework64 -Clr2 -Clr4
Sets the ExampleUrl app setting in the following machine.config files:
* `%SYSTEMROOT%\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config`
* `%SYSTEMROOT%\Microsoft.NET\Framework64\v2.0.50727\CONFIG\machine.config`
* `%SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319\CONFIG\machine.config`
* `%SYSTEMROOT%\Microsoft.NET\Framework64\v4.0.30319\CONFIG\machine.config`
.LINK
Remove-DotNetAppSetting
.LINK
Set-DotNetConnectionString
.EXAMPLE
> Set-DotNetAppSetting -Name ExampleUrl -Value example.com -Framework64 -Clr4
Sets the ExampleUrl app setting in the following machine.config file:
* `%SYSTEMROOT%\Microsoft.NET\Framework64\v4.0.30319\CONFIG\machine.config`
#>
[CmdletBinding(SupportsShouldProcess=$true, DefaultParameterSetName='All')]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the app setting to be set
$Name,
[Parameter(Mandatory=$true)]
[string]
# The valie of the app setting to be set.
$Value,
[Switch]
# Set the app setting in the 32-bit machine.config.
$Framework,
[Switch]
# Set the app setting in the 64-bit machine.config. Ignored if running on a 32-bit operating system.
$Framework64,
[Switch]
# Set the app setting in the .NET 2.0 machine.config.
$Clr2,
[Switch]
# Set the app setting in the .NET 4.0 machine.config.
$Clr4
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not ($Framework -or $Framework64) )
{
Write-Error "You must supply either or both of the Framework and Framework64 switches."
return
}
if( -not ($Clr2 -or $Clr4) )
{
Write-Error "You must supply either or both of the Clr2 and Clr4 switches."
return
}
$runtimes = @()
if( $Clr2 )
{
$runtimes += 'v2.0'
}
if( $Clr4 )
{
$runtimes += 'v4.0'
}
$runtimes | ForEach-Object {
$params = @{
FilePath = (Join-Path $CarbonBinDir 'Set-DotNetAppSetting.ps1' -Resolve);
ArgumentList = @(
(ConvertTo-Base64 -Value $Name),
(ConvertTo-Base64 -Value $Value)
);
Runtime = $_;
ExecutionPolicy = [Microsoft.PowerShell.ExecutionPolicy]::RemoteSigned;
}
if( $Framework )
{
Invoke-PowerShell @params -x86
}
if( $Framework64 )
{
Invoke-PowerShell @params
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-DotNetConnectionString
{
<#
.SYNOPSIS
Sets a named connection string in the .NET machine.config file
.DESCRIPTION
The connection string setting can be set in up to four different machine.config files:
* .NET 2.0 32-bit (switches -Clr2 -Framework)
* .NET 2.0 64-bit (switches -Clr2 -Framework64)
* .NET 4.0 32-bit (switches -Clr4 -Framework)
* .NET 4.0 64-bit (switches -Clr4 -Framework64)
Any combination of Framework and Clr switch can be used, but you MUST supply one of each.
.LINK
Set-DotNetAppSetting
.LINK
Remove-DotNetAppSetting
.EXAMPLE
> Set-DotNetConnectionString -Name DevDB -Value "data source=.\DevDB;Integrated Security=SSPI;" -Framework -Framework64 -Clr2 -Clr4
Sets the DevDB connection string in the following machine.config files:
* `%SYSTEMROOT%\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config`
* `%SYSTEMROOT%\Microsoft.NET\Framework64\v2.0.50727\CONFIG\machine.config`
* `%SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319\CONFIG\machine.config`
* `%SYSTEMROOT%\Microsoft.NET\Framework64\v4.0.30319\CONFIG\machine.config`
.EXAMPLE
> Set-DotNetConnectionString -Name DevDB -Value "data source=.\DevDB;Integrated Security=SSPI;" -Framework64 -Clr4
Sets the DevDB connection string in the `%SYSTEMROOT%\Microsoft.NET\Framework64\v4.0.30319\CONFIG\machine.config` machine.config file to:
<add name="DevDB" connectionString="data source=.\DevDB;Integrated Security=SSPI;" />
.EXAMPLE
Set-DotNetConnectionString -Name Prod -Value "data source=proddb\Prod;Integrated Security=SSPI" -ProviderName 'System.Data.SqlClient' -Framework -Clr2
Creates the following connection string in the `%SYSTEMROOT%\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config` file:
<add name="Prod" connectionString="data source=proddb\Prod;Integrated Security=SSPI" providerName="System.Data.SqlClient" />
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the .net connection string to be set
$Name,
[Parameter(Mandatory=$true)]
[string]
# The connection string to be set.
$Value,
[string]
# The provider name for the connection string.
$ProviderName,
[Switch]
# Set the connection string in the 32-bit machine.config.
$Framework,
[Switch]
# Set the connection string in the 64-bit machine.config
$Framework64,
[Switch]
# Set the app setting in the .NET 2.0 machine.config. This flag won't work under PowerShell 3.0.
$Clr2,
[Switch]
# Set the app setting in the .NET 4.0 machine.config.
$Clr4
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not ($Framework -or $Framework64) )
{
Write-Error "You must supply either or both of the Framework and Framework64 switches."
return
}
if( -not ($Clr2 -or $Clr4) )
{
Write-Error "You must supply either or both of the Clr2 and Clr4 switches."
return
}
$runtimes = @()
if( $Clr2 )
{
$runtimes += 'v2.0'
}
if( $Clr4 )
{
$runtimes += 'v4.0'
}
$runtimes | ForEach-Object {
$params = @{
FilePath = (Join-Path $CarbonBinDir 'Set-DotNetConnectionString.ps1' -Resolve);
ArgumentList = @(
(ConvertTo-Base64 -Value $Name),
(ConvertTo-Base64 -Value $Value),
(ConvertTo-Base64 -Value $ProviderName)
);
Runtime = $_;
ExecutionPolicy = [Microsoft.PowerShell.ExecutionPolicy]::RemoteSigned;
}
if( $Framework )
{
Invoke-PowerShell @params -x86
}
if( $Framework64 )
{
Invoke-PowerShell @params
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-EnvironmentVariable
{
<#
.SYNOPSIS
Creates or sets an environment variable.
.DESCRIPTION
Uses the .NET [Environment class](http://msdn.microsoft.com/en-us/library/z8te35sa) to create or set an environment variable in the Process, User, or Machine scopes.
Changes to environment variables in the User and Machine scope are not picked up by running processes. Any running processes that use this environment variable should be restarted.
.LINK
Carbon_EnvironmentVariable
.LINK
Remove-EnvironmentVariable
.LINK
http://msdn.microsoft.com/en-us/library/z8te35sa
.EXAMPLE
Set-EnvironmentVariable -Name 'MyEnvironmentVariable' -Value 'Value1' -ForProcess
Creates the `MyEnvironmentVariable` with an initial value of `Value1` in the process scope, i.e. the variable is only accessible in the current process.
.EXAMPLE
Set-EnvironmentVariable -Name 'MyEnvironmentVariable' -Value 'Value1' -ForComputer
Creates the `MyEnvironmentVariable` with an initial value of `Value1` in the machine scope, i.e. the variable is accessible in all newly launched processes.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of environment variable to add/set.
$Name,
[Parameter(Mandatory=$true)]
[string]
# The environment variable's value.
$Value,
# Sets the environment variable for the current process.
[Switch]
$ForProcess,
# Sets the environment variable for the current user.
[Switch]
$ForUser,
# Sets the environment variable for the current computer.
[Switch]
$ForComputer
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not $ForProcess -and -not $ForUser -and -not $ForComputer )
{
Write-Error -Message ('Environment variable target not specified. You must supply one of the ForComputer, ForUser, or ForProcess switches.')
return
}
Invoke-Command -ScriptBlock {
if( $ForComputer )
{
[EnvironmentVariableTarget]::Machine
}
if( $ForUser )
{
[EnvironmentVariableTarget]::User
}
if( $ForProcess )
{
[EnvironmentVariableTarget]::Process
}
} |
ForEach-Object {
$target = $_
if( $PSCmdlet.ShouldProcess( "$target-level environment variable '$Name'", "set") )
{
[Environment]::SetEnvironmentVariable( $Name, $Value, $target )
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-HostsEntry
{
<#
.SYNOPSIS
Sets a hosts entry in a hosts file.
.DESCRIPTION
Sets the IP address for a given hostname. If the hostname doesn't exist in the hosts file, appends a new entry to the end. If the hostname does exist, its IP address gets updated. If you supply a description, it is appended to the line as a comment.
If any duplicate hosts entries are found, they are commented out; Windows uses the first duplicate entry.
This function scans the entire hosts file. If you have a large hosts file, and are updating multiple entries, this function will be slow.
You can operate on a custom hosts file, too. Pass its path with the `Path` parameter.
Sometimes the system's hosts file is in use and locked when you try to update it. The `Set-HostsEntry` function tries 10 times to set a hosts entry before giving up and writing an error. It waits a random amount of time (from 0 to 1000 milliseconds) between each attempt.
.EXAMPLE
Set-HostsEntry -IPAddress 10.2.3.4 -HostName 'myserver' -Description "myserver's IP address"
If your hosts file contains the following:
127.0.0.1 localhost
After running this command, it will contain the following:
127.0.0.1 localhost
10.2.3.4 myserver # myserver's IP address
.EXAMPLE
Set-HostsEntry -IPAddress 10.5.6.7 -HostName 'myserver'
If your hosts file contains the following:
127.0.0.1 localhost
10.2.3.4 myserver # myserver's IP address
After running this command, it will contain the following:
127.0.0.1 localhost
10.5.6.7 myserver
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[Net.IPAddress]
# The IP address for the hosts entry.
$IPAddress,
[Parameter(Mandatory=$true)]
[string]
# The hostname for the hosts entry.
$HostName,
[string]
# An optional description of the hosts entry.
$Description,
[string]
# The path to the hosts file where the entry should be set. Defaults to the local computer's hosts file.
$Path = (Get-PathToHostsFile)
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$matchPattern = '^(?<IP>[0-9a-f.:]+)\s+(?<HostName>[^\s#]+)(?<Tail>.*)$'
$lineFormat = "{0,-16}{1}{2}"
if(-not (Test-Path $Path))
{
Write-Warning "Creating hosts file at: $Path"
New-Item $Path -ItemType File
}
[string[]]$lines = Read-File -Path $Path -ErrorVariable 'cmdErrors'
if( $cmdErrors )
{
return
}
$outLines = New-Object 'Collections.ArrayList'
$found = $false
$lineNum = 0
$updateHostsFile = $false
foreach($line in $lines)
{
$lineNum += 1
if($line.Trim().StartsWith("#") -or ($line.Trim() -eq '') )
{
[void] $outlines.Add($line)
}
elseif($line -match $matchPattern)
{
$ip = $matches["IP"]
$hn = $matches["HostName"]
$tail = $matches["Tail"].Trim()
if( $HostName -eq $hn )
{
if($found)
{
#this is a duplicate so, let's comment it out
[void] $outlines.Add("#$line")
$updateHostsFile = $true
continue
}
$ip = $IPAddress
$tail = if( $Description ) { "`t# $Description" } else { '' }
$found = $true
}
else
{
$tail = "`t{0}" -f $tail
}
if( $tail.Trim() -eq "#" )
{
$tail = ""
}
$outline = $lineformat -f $ip, $hn, $tail
$outline = $outline.Trim()
if( $outline -ne $line )
{
$updateHostsFile = $true
}
[void] $outlines.Add($outline)
}
else
{
Write-Warning ("Hosts file {0}: line {1}: invalid entry: {2}" -f $Path,$lineNum,$line)
$outlines.Add( ('# {0}' -f $line) )
}
}
if(-not $found)
{
#add a new entry
$tail = "`t# $Description"
if($tail.Trim() -eq "#")
{
$tail = ""
}
$outline = $lineformat -f $IPAddress, $HostName, $tail
$outline = $outline.Trim()
[void] $outlines.Add($outline)
$updateHostsFile = $true
}
if( -not $updateHostsFile )
{
return
}
Write-Verbose -Message ('[HOSTS] [{0}] {1,-15} {2}' -f $Path,$IPAddress,$HostName)
$outLines | Write-File -Path $Path
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-IisHttpHeader
{
<#
.SYNOPSIS
Sets an HTTP header for a website or a directory under a website.
.DESCRIPTION
If the HTTP header doesn't exist, it is created. If a header exists, its value is replaced.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
Get-IisHttpHeader
.EXAMPLE
Set-IisHttpHeader -SiteName 'SopwithCamel' -Name 'X-Flown-By' -Value 'Snoopy'
Sets or creates the `SopwithCamel` website's `X-Flown-By` HTTP header to the value `Snoopy`.
.EXAMPLE
Set-IisHttpHeader -SiteName 'SopwithCamel' -VirtualPath 'Engine' -Name 'X-Powered-By' -Value 'Root Beer'
Sets or creates the `SopwithCamel` website's `Engine` sub-directory's `X-Powered-By` HTTP header to the value `Root Beer`.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the website where the HTTP header should be set/created.
$SiteName,
[Alias('Path')]
[string]
# The optional path under `SiteName` where the HTTP header should be set/created.
$VirtualPath = '',
[Parameter(Mandatory=$true)]
[string]
# The name of the HTTP header.
$Name,
[Parameter(Mandatory=$true)]
[string]
# The value of the HTTP header.
$Value
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$httpProtocol = Get-IisConfigurationSection -SiteName $SiteName `
-VirtualPath $VirtualPath `
-SectionPath 'system.webServer/httpProtocol'
$headers = $httpProtocol.GetCollection('customHeaders')
$header = $headers | Where-Object { $_['name'] -eq $Name }
if( $header )
{
$action = 'setting'
$header['name'] = $Name
$header['value'] = $Value
}
else
{
$action = 'adding'
$addElement = $headers.CreateElement( 'add' )
$addElement['name'] = $Name
$addElement['value'] = $Value
[void] $headers.Add( $addElement )
}
$fullPath = Join-IisVirtualPath $SiteName $VirtualPath
if( $pscmdlet.ShouldProcess( $fullPath, ('{0} HTTP header {1}' -f $action,$Name) ) )
{
$httpProtocol.CommitChanges()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-IisHttpRedirect
{
<#
.SYNOPSIS
Turns on HTTP redirect for all or part of a website.
.DESCRIPTION
Configures all or part of a website to redirect all requests to another website/URL. By default, it operates on a specific website. To configure a directory under a website, set `VirtualPath` to the virtual path of that directory.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
http://www.iis.net/configreference/system.webserver/httpredirect#005
.LINK
http://technet.microsoft.com/en-us/library/cc732969(v=WS.10).aspx
.EXAMPLE
Set-IisHttpRedirect -SiteName Peanuts -Destination 'http://new.peanuts.com'
Redirects all requests to the `Peanuts` website to `http://new.peanuts.com`.
.EXAMPLE
Set-IisHttpRedirect -SiteName Peanuts -VirtualPath Snoopy/DogHouse -Destination 'http://new.peanuts.com'
Redirects all requests to the `/Snoopy/DogHouse` path on the `Peanuts` website to `http://new.peanuts.com`.
.EXAMPLE
Set-IisHttpRedirect -SiteName Peanuts -Destination 'http://new.peanuts.com' -StatusCode 'Temporary'
Redirects all requests to the `Peanuts` website to `http://new.peanuts.com` with a temporary HTTP status code. You can also specify `Found` (HTTP 302), or `Permanent` (HTTP 301).
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The site where the redirection should be setup.
$SiteName,
[Alias('Path')]
[string]
# The optional path where redirection should be setup.
$VirtualPath = '',
[Parameter(Mandatory=$true)]
[string]
# The destination to redirect to.
$Destination,
[Carbon.Iis.HttpResponseStatus]
# The HTTP status code to use. Default is `Found`. Should be one of `Found` (HTTP 302), `Permanent` (HTTP 301), or `Temporary` (HTTP 307).
[Alias('StatusCode')]
$HttpResponseStatus = [Carbon.Iis.HttpResponseStatus]::Found,
[Switch]
# Redirect all requests to exact destination (instead of relative to destination). I have no idea what this means. [Maybe TechNet can help.](http://technet.microsoft.com/en-us/library/cc732969(v=WS.10).aspx)
$ExactDestination,
[Switch]
# Only redirect requests to content in site and/or path, but nothing below it. I have no idea what this means. [Maybe TechNet can help.](http://technet.microsoft.com/en-us/library/cc732969(v=WS.10).aspx)
$ChildOnly
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$settings = Get-IisHttpRedirect -SiteName $SiteName -Path $VirtualPath
$settings.Enabled = $true
$settings.Destination = $destination
$settings.HttpResponseStatus = $HttpResponseStatus
$settings.ExactDestination = $ExactDestination
$settings.ChildOnly = $ChildOnly
if( $pscmdlet.ShouldProcess( (Join-IisVirtualPath $SiteName $VirtualPath), "set HTTP redirect settings" ) )
{
$settings.CommitChanges()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-IisMimeMap
{
<#
.SYNOPSIS
Creates or sets a file extension to MIME type map for an entire web server.
.DESCRIPTION
IIS won't serve static files unless they have an entry in the MIME map. Use this function to create/update a MIME map entry.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
Get-IisMimeMap
.LINK
Remove-IisMimeMap
.EXAMPLE
Set-IisMimeMap -FileExtension '.m4v' -MimeType 'video/x-m4v'
Adds a MIME map so that IIS will serve `.m4v` files as `video/x-m4v`.
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='ForWebServer')]
param(
[Parameter(Mandatory=$true,ParameterSetName='ForWebsite')]
[string]
# The name of the website whose MIME type to set.
$SiteName,
[Parameter(ParameterSetName='ForWebsite')]
[string]
# The optional site path whose configuration should be returned.
$VirtualPath = '',
[Parameter(Mandatory=$true)]
[string]
# The file extension to set.
$FileExtension,
[Parameter(Mandatory=$true)]
[string]
# The MIME type to serve the files as.
$MimeType
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$getIisConfigSectionParams = @{ }
if( $PSCmdlet.ParameterSetName -eq 'ForWebsite' )
{
$getIisConfigSectionParams['SiteName'] = $SiteName
$getIisConfigSectionParams['VirtualPath'] = $VirtualPath
}
$staticContent = Get-IisConfigurationSection -SectionPath 'system.webServer/staticContent' @getIisConfigSectionParams
$mimeMapCollection = $staticContent.GetCollection()
$mimeMap = $mimeMapCollection | Where-Object { $_['fileExtension'] -eq $FileExtension }
if( $mimeMap )
{
$action = 'setting'
$mimeMap['fileExtension'] = $FileExtension
$mimeMap['mimeType'] = $MimeType
}
else
{
$action = 'adding'
$mimeMap = $mimeMapCollection.CreateElement("mimeMap");
$mimeMap["fileExtension"] = $FileExtension
$mimeMap["mimeType"] = $MimeType
[void] $mimeMapCollection.Add($mimeMap)
}
if( $PSCmdlet.ShouldProcess( 'IIS web server', ('{0} MIME map {1} -> {2}' -f $action,$FileExtension,$MimeType) ) )
{
$staticContent.CommitChanges()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-IisWebsiteID
{
<#
.SYNOPSIS
Sets a website's ID to an explicit number.
.DESCRIPTION
IIS handles assigning websites individual IDs. This method will assign a website explicit ID you manage (e.g. to support session sharing in a web server farm).
If another site already exists with that ID, you'll get an error.
When you change a website's ID, IIS will stop the site, but not start the site after saving the ID change. This function waits until the site's ID is changed, and then will start the website.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Set-IisWebsiteID -SiteName Holodeck -ID 483
Sets the `Holodeck` website's ID to `483`.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The website name.
$SiteName,
[Parameter(Mandatory=$true)]
[int]
# The website's new ID.
$ID
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-IisWebsite -Name $SiteName) )
{
Write-Error ('Website {0} not found.' -f $SiteName)
return
}
$websiteWithID = Get-IisWebsite | Where-Object { $_.ID -eq $ID -and $_.Name -ne $SiteName }
if( $websiteWithID )
{
Write-Error -Message ('ID {0} already in use for website {1}.' -f $ID,$SiteName) -Category ResourceExists
return
}
$website = Get-IisWebsite -SiteName $SiteName
$startWhenDone = $false
if( $website.ID -ne $ID )
{
if( $PSCmdlet.ShouldProcess( ('website {0}' -f $SiteName), ('set site ID to {0}' -f $ID) ) )
{
$startWhenDone = ($website.State -eq 'Started')
$website.ID = $ID
$website.CommitChanges()
}
}
if( $PSBoundParameters.ContainsKey('WhatIf') )
{
return
}
# Make sure the website's ID gets updated
$website = $null
$maxTries = 100
$numTries = 0
do
{
Start-Sleep -Milliseconds 100
$website = Get-IisWebsite -SiteName $SiteName
if( $website -and $website.ID -eq $ID )
{
break
}
$numTries++
}
while( $numTries -lt $maxTries )
if( -not $website -or $website.ID -ne $ID )
{
Write-Error ('IIS:/{0}: site ID hasn''t changed to {1} after waiting 10 seconds. Please check IIS configuration.' -f $SiteName,$ID)
}
if( -not $startWhenDone )
{
return
}
# Now, start the website.
$numTries = 0
do
{
# Sometimes, the website is invalid and Start() throws an exception.
try
{
if( $website )
{
$null = $website.Start()
}
}
catch
{
$website = $null
}
Start-Sleep -Milliseconds 100
$website = Get-IisWebsite -SiteName $SiteName
if( $website -and $website.State -eq 'Started' )
{
break
}
$numTries++
}
while( $numTries -lt $maxTries )
if( -not $website -or $website.State -ne 'Started' )
{
Write-Error ('IIS:/{0}: failed to start website after setting ID to {1}' -f $SiteName,$ID)
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-IisWebsiteSslCertificate
{
<#
.SYNOPSIS
Sets a website's SSL certificate.
.DESCRIPTION
SSL won't work on a website if an SSL certificate hasn't been bound to all the IP addresses it's listening on. This function binds a certificate to all a website's IP addresses. Make sure you call this method *after* you create a website's bindings. Any previous SSL bindings on those IP addresses are deleted.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Set-IisWebsiteSslCertificate -SiteName Peanuts -Thumbprint 'a909502dd82ae41433e6f83886b00d4277a32a7b' -ApplicationID $PeanutsAppID
Binds the certificate whose thumbprint is `a909502dd82ae41433e6f83886b00d4277a32a7b` to the `Peanuts` website. It's a good idea to re-use the same GUID for each distinct application.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the website whose SSL certificate is being set.
$SiteName,
[Parameter(Mandatory=$true)]
[string]
# The thumbprint of the SSL certificate to use.
$Thumbprint,
[Parameter(Mandatory=$true)]
[Guid]
# A GUID that uniquely identifies this website. Create your own.
$ApplicationID
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$site = Get-IisWebsite -SiteName $SiteName
if( -not $site )
{
Write-Error "Unable to find website '$SiteName'."
return
}
$site.Bindings | Where-Object { $_.Protocol -eq 'https' } | ForEach-Object {
$installArgs = @{ }
if( $_.Endpoint.Address -ne '0.0.0.0' )
{
$installArgs.IPAddress = $_.Endpoint.Address.ToString()
}
if( $_.Endpoint.Port -ne '*' )
{
$installArgs.Port = $_.Endpoint.Port
}
Set-SslCertificateBinding @installArgs -ApplicationID $ApplicationID -Thumbprint $Thumbprint
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-IisWindowsAuthentication
{
<#
.SYNOPSIS
Configures the settings for Windows authentication.
.DESCRIPTION
By default, configures Windows authentication on a website. You can configure Windows authentication at a specific path under a website by passing the virtual path (*not* the physical path) to that directory.
The changes only take effect if Windows authentication is enabled (see `Enable-IisSecurityAuthentication`).
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.LINK
http://blogs.msdn.com/b/webtopics/archive/2009/01/19/service-principal-name-spn-checklist-for-kerberos-authentication-with-iis-7-0.aspx
.LINK
Disable-IisSecurityAuthentication
.LINK
Enable-IisSecurityAuthentication
.EXAMPLE
Set-IisWindowsAuthentication -SiteName Peanuts
Configures Windows authentication on the `Peanuts` site to use kernel mode.
.EXAMPLE
Set-IisWindowsAuthentication -SiteName Peanuts -VirtualPath Snoopy/DogHouse -DisableKernelMode
Configures Windows authentication on the `Doghouse` directory of the `Peanuts` site to not use kernel mode.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The site where Windows authentication should be set.
$SiteName,
[Alias('Path')]
[string]
# The optional path where Windows authentication should be set.
$VirtualPath = '',
[Switch]
# Turn on kernel mode. Default is false. [More information about Kerndel Mode authentication.](http://blogs.msdn.com/b/webtopics/archive/2009/01/19/service-principal-name-spn-checklist-for-kerberos-authentication-with-iis-7-0.aspx)
$DisableKernelMode
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$useKernelMode = 'True'
if( $DisableKernelMode )
{
$useKernelMode = 'False'
}
$authSettings = Get-IisSecurityAuthentication -SiteName $SiteName -VirtualPath $VirtualPath -Windows
$authSettings.SetAttributeValue( 'useKernelMode', $useKernelMode )
$fullPath = Join-IisVirtualPath $SiteName $VirtualPath
if( $pscmdlet.ShouldProcess( $fullPath, "set Windows authentication" ) )
{
$authSettings.CommitChanges()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-IniEntry
{
<#
.SYNOPSIS
Sets an entry in an INI file.
.DESCRIPTION
A configuration file consists of sections, led by a `[section]` header and followed by `name = value` entries. This function creates or updates an entry in an INI file. Something like this:
[ui]
username = Regina Spektor <[email protected]>
[extensions]
share =
extdiff =
Names are not allowed to contains the equal sign, `=`. Values can contain any character. The INI file is parsed using `Split-Ini`. [See its documentation for more examples.](Split-Ini.html)
Be default, operates on the INI file case-insensitively. If your INI is case-sensitive, use the `-CaseSensitive` switch.
.LINK
Split-Ini
LINK
Remove-IniEntry
.EXAMPLE
Set-IniEntry -Path C:\Users\rspektor\mercurial.ini -Section extensions -Name share -Value ''
If the `C:\Users\rspektor\mercurial.ini` file is empty, adds the following to it:
[extensions]
share =
.EXAMPLE
Set-IniEntry -Path C:\Users\rspektor\music.ini -Name genres -Value 'alternative,rock'
If the `music.ini` file is empty, adds the following to it:
genres = alternative,rock
.EXAMPLE
Set-IniEntry -Path C:\Users\rspektor\music.ini -Name genres -Value 'alternative,rock,world'
If the `music.ini` file contains the following:
genres = r&b
After running this command, `music.ini` will look like this:
genres = alternative,rock,world
.EXAMPLE
Set-IniEntry -Path C:\users\me\npmrc -Name prefix -Value 'C:\Users\me\npm_modules' -CaseSensitive
Demonstrates how to set an INI entry in a case-sensitive file.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to the INI file to set.
$Path,
[Parameter(Mandatory=$true)]
[string]
# The name of the INI entry being set.
$Name,
[string]
# The value of the INI entry being set.
$Value,
[string]
# The section of the INI where the entry should be set.
$Section,
[Switch]
# Treat the INI file in a case-sensitive manner.
$CaseSensitive
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $Name -like '*=*' )
{
Write-Error "INI entry name '$Name' invalid: can not contain equal sign '='."
return
}
$settings = @{ }
$lines = New-Object 'Collections.ArrayList'
if( Test-Path $Path -PathType Leaf )
{
$settings = Split-Ini -Path $Path -AsHashtable -CaseSensitive:$CaseSensitive
Get-Content -Path $Path | ForEach-Object { [void] $lines.Add( $_ ) }
}
$settings.Values |
Add-Member -MemberType NoteProperty -Name 'Updated' -Value $false -PassThru |
Add-Member -MemberType NoteProperty -Name 'IsNew' -Value $false
$key = "$Name"
if( $Section )
{
$key = "$Section.$Name"
}
if( $settings.ContainsKey( $key ) )
{
$setting = $settings[$key]
if( $setting.Value -cne $Value )
{
Write-Verbose -Message "Updating INI entry '$key' in '$Path'."
$lines[$setting.LineNumber - 1] = "$Name = $Value"
}
}
else
{
$lastItemInSection = $settings.Values | `
Where-Object { $_.Section -eq $Section } | `
Sort-Object -Property LineNumber | `
Select-Object -Last 1
$newLine = "$Name = $Value"
Write-Verbose -Message "Creating INI entry '$key' in '$Path'."
if( $lastItemInSection )
{
$idx = $lastItemInSection.LineNumber
$lines.Insert( $idx, $newLine )
if( $lines.Count -gt ($idx + 1) -and $lines[$idx + 1])
{
$lines.Insert( $idx + 1, '' )
}
}
else
{
if( $Section )
{
if( $lines.Count -gt 1 -and $lines[$lines.Count - 1] )
{
[void] $lines.Add( '' )
}
if(-not $lines.Contains("[$Section]"))
{
[void] $lines.Add( "[$Section]" )
[void] $lines.Add( $newLine )
}
else
{
for ($i=0; $i -lt $lines.Count; $i++)
{
if ($lines[$i] -eq "[$Section]")
{
$lines.Insert($i+1, $newLine)
break
}
}
}
}
else
{
$lines.Insert( 0, $newLine )
if( $lines.Count -gt 1 -and $lines[1] )
{
$lines.Insert( 1, '' )
}
}
}
}
$lines | Set-Content -Path $Path
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-RegistryKeyValue
{
<#
.SYNOPSIS
Sets a value in a registry key.
.DESCRIPTION
The `Set-RegistryKeyValue` function sets the value of a registry key. If the key doesn't exist, it is created first. Uses PowerShell's `New-ItemPropery` to create the value if doesn't exist. Otherwise uses `Set-ItemProperty` to set the value.
`DWord` and `QWord` values are stored in the registry as unsigned integers. If you pass a negative integer for the `DWord` and `QWord` parameters, PowerShell will convert it to an unsigned integer before storing. You won't get the same negative number back.
To store integer values greater than `[Int32]::MaxValue` or `[Int64]::MaxValue`, use the `UDWord` and `UQWord` parameters, respectively, which are unsigned integers. These parameters were in Carbon 2.0.
In versions of Carbon before 2.0, you'll need to convert these large unsigned integers into signed integers. You can't do this with casting. Casting preservers the value, not the bits underneath. You need to re-interpret the bits. Here's some sample code:
# Carbon 1.0
$bytes = [BitConverter]::GetBytes( $unsignedInt )
$signedInt = [BitConverter]::ToInt32( $bytes, 0 ) # Or use `ToInt64` if you're working with 64-bit/QWord values
Set-RegistryKeyValue -Path $Path -Name 'MyUnsignedDWord' -DWord $signedInt
# Carbon 2.0
Set-RegistryKeyValue -Path $Path -Name 'MyUnsignedDWord' -UDWord $unsignedInt
.LINK
Get-RegistryKeyValue
.LINK
Test-RegistryKeyValue
.EXAMPLE
Set-RegistryKeyValue -Path 'hklm:\Software\Carbon\Test -Name Status -String foobar
Creates the `Status` string value under the `hklm:\Software\Carbon\Test` key and sets its value to `foobar`.
.EXAMPLE
Set-RegistryKeyValue -Path 'hklm:\Software\Carbon\Test -Name ComputerName -String '%ComputerName%' -Expand
Creates an expandable string. When retrieving this value, environment variables will be expanded.
.EXAMPLE
Set-RegistryKeyValue -Path 'hklm:\Software\Carbon\Test -Name Movies -String ('Signs','Star Wars','Raiders of the Lost Ark')
Sets a multi-string (i.e. array) value.
.EXAMPLE
Set-RegistryKeyValue -Path hklm:\Software\Carbon\Test -Name 'SomeBytes' -Binary ([byte[]]@( 1, 2, 3, 4))
Sets a binary value (i.e. `REG_BINARY`).
.EXAMPLE
Set-RegistryKeyValue -Path hklm:\Software\Carbon\Test -Name 'AnInt' -DWord 48043
Sets a binary value (i.e. `REG_DWORD`).
.EXAMPLE
Set-RegistryKeyValue -Path hklm:\Software\Carbon\Test -Name 'AnInt64' -QWord 9223372036854775807
Sets a binary value (i.e. `REG_QWORD`).
.EXAMPLE
Set-RegistryKeyValue -Path hklm:\Software\Carbon\Test -Name 'AnUnsignedInt' -UDWord [uint32]::MaxValue
Demonstrates how to set a registry value with an unsigned integer or an integer bigger than `[int]::MaxValue`.
The `UDWord` parameter was added in Carbon 2.0. In earlier versions of Carbon, you have to convert the unsigned int's bits to a signed integer:
$bytes = [BitConverter]::GetBytes( $unsignedInt )
$signedInt = [BitConverter]::ToInt32( $bytes, 0 )
Set-RegistryKeyValue -Path $Path -Name 'MyUnsignedDWord' -DWord $signedInt
.EXAMPLE
Set-RegistryKeyValue -Path hklm:\Software\Carbon\Test -Name 'AnUnsignedInt64' -UQWord [uint64]::MaxValue
Demonstrates how to set a registry value with an unsigned 64-bit integer or a 64-bit integer bigger than `[long]::MaxValue`.
The `UQWord parameter was added in Carbon 2.0. In earlier versions of Carbon, you have to convert the unsigned int's bits to a signed integer:
$bytes = [BitConverter]::GetBytes( $unsignedInt )
$signedInt = [BitConverter]::ToInt64( $bytes, 0 )
Set-RegistryKeyValue -Path $Path -Name 'MyUnsignedDWord' -DWord $signedInt
.EXAMPLE
Set-RegistryKeyValue -Path hklm:\Software\Carbon\Test -Name 'UsedToBeAStringNowShouldBeDWord' -DWord 1 -Force
Uses the `Force` parameter to delete the existing `UsedToBeAStringNowShouldBeDWord` before re-creating it. This flag is useful if you need to change the type of a registry value.
#>
[CmdletBinding(SupportsShouldPRocess=$true,DefaultParameterSetName='String')]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to the registry key where the value should be set. Will be created if it doesn't exist.
$Path,
[Parameter(Mandatory=$true)]
[string]
# The name of the value being set.
$Name,
[Parameter(Mandatory=$true,ParameterSetName='String')]
[string]
# The value's data. Creates a value for holding string data (i.e. `REG_SZ`).
$String,
[Parameter(ParameterSetName='String')]
[Switch]
# The string should be expanded when retrieved. Creates a value for holding expanded string data (i.e. `REG_EXPAND_SZ`).
$Expand,
[Parameter(Mandatory=$true,ParameterSetName='Binary')]
[byte[]]
# The value's data. Creates a value for holding binary data (i.e. `REG_BINARY`).
$Binary,
[Parameter(Mandatory=$true,ParameterSetName='DWord')]
[int]
# The value's data. Creates a value for holding a 32-bit integer (i.e. `REG_DWORD`).
$DWord,
[Parameter(Mandatory=$true,ParameterSetName='DWordAsUnsignedInt')]
[uint32]
# The value's data as an unsigned integer (i.e. `UInt32`). Creates a value for holding a 32-bit integer (i.e. `REG_DWORD`).
$UDWord,
[Parameter(Mandatory=$true,ParameterSetName='QWord')]
[long]
# The value's data. Creates a value for holding a 64-bit integer (i.e. `REG_QWORD`).
$QWord,
[Parameter(Mandatory=$true,ParameterSetName='QWordAsUnsignedInt')]
[uint64]
# The value's data as an unsigned long (i.e. `UInt64`). Creates a value for holding a 64-bit integer (i.e. `REG_QWORD`).
$UQWord,
[Parameter(Mandatory=$true,ParameterSetName='MultiString')]
[string[]]
# The value's data. Creates a value for holding an array of strings (i.e. `REG_MULTI_SZ`).
$Strings,
[Switch]
# Removes and re-creates the value. Useful for changing a value's type.
$Force,
[Parameter(DontShow=$true)]
[Switch]
# OBSOLETE. Will be removed in a future version of Carbon.
$Quiet
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSBoundParameters.ContainsKey('Quiet') )
{
Write-Warning ('Set-RegistryKeyValue''s -Quiet switch is obsolete and will be removed in a future version of Carbon. Please remove usages.')
}
$value = $null
$type = $pscmdlet.ParameterSetName
switch -Exact ( $pscmdlet.ParameterSetName )
{
'String'
{
$value = $String
if( $Expand )
{
$type = 'ExpandString'
}
}
'Binary' { $value = $Binary }
'DWord' { $value = $DWord }
'QWord' { $value = $QWord }
'DWordAsUnsignedInt'
{
$value = $UDWord
$type = 'DWord'
}
'QWordAsUnsignedInt'
{
$value = $UQWord
$type = 'QWord'
}
'MultiString' { $value = $Strings }
}
Install-RegistryKey -Path $Path
if( $Force )
{
Remove-RegistryKeyValue -Path $Path -Name $Name
}
if( Test-RegistryKeyValue -Path $Path -Name $Name )
{
$currentValue = Get-RegistryKeyValue -Path $Path -Name $Name
if( $currentValue -ne $value )
{
Write-Verbose -Message ("[{0}@{1}] {2} -> {3}'" -f $Path,$Name,$currentValue,$value)
Set-ItemProperty -Path $Path -Name $Name -Value $value
}
}
else
{
Write-Verbose -Message ("[{0}@{1}] -> {2}'" -f $Path,$Name,$value)
$null = New-ItemProperty -Path $Path -Name $Name -Value $value -PropertyType $type
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-ServiceAcl
{
<#
.SYNOPSIS
Sets a service's discretionary access control list (i.e. DACL).
.DESCRIPTION
The existing DACL is replaced with the new DACL. No previous permissions are preserved. That's your job. You're warned!
You probably want `Grant-ServicePermission` or `Revoke-ServicePermission` instead.
.LINK
Get-ServicePermission
.LINK
Grant-ServicePermission
.LINK
Revoke-ServicePermission
.EXAMPLE
Set-ServiceDacl -Name 'Hyperdrive' -Dacl $dacl
Replaces the DACL on the `Hyperdrive` service. Yikes! Sounds like something the Empire would do, though.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The service whose DACL to replace.
$Name,
[Parameter(Mandatory=$true)]
[Security.AccessControl.DiscretionaryAcl]
# The service's new DACL.
$Dacl
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$rawSD = Get-ServiceSecurityDescriptor -Name $Name
$daclBytes = New-Object byte[] $Dacl.BinaryLength
$Dacl.GetBinaryForm($daclBytes, 0);
$rawSD.DiscretionaryAcl = New-Object Security.AccessControl.RawAcl $daclBytes,0
$sdBytes = New-Object byte[] $rawSD.BinaryLength
$rawSD.GetBinaryForm($sdBytes, 0);
if( $pscmdlet.ShouldProcess( ("{0} service DACL" -f $Name), "set" ) )
{
[Carbon.Service.ServiceSecurity]::SetServiceSecurityDescriptor( $Name, $sdBytes )
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-SslCertificateBinding
{
<#
.SYNOPSIS
Sets an SSL certificate binding for a given IP/port.
.DESCRIPTION
Uses the netsh command line application to set the certificate for an IP address and port. If a binding already exists for the IP/port, it is removed, and the new binding is created.
Beginning with Carbon 2.0, returns a `Carbon.Certificates.SslCertificateBinding` object for the binding that was set.
.OUTPUTS
Carbon.Certificates.SslCertificateBinding.
.EXAMPLE
Set-SslCertificateBinding -IPAddress 43.27.89.54 -Port 443 -ApplicationID 88d1f8da-aeb5-40a2-a5e5-0e6107825df7 -Thumbprint 4789073458907345907434789073458907345907
Configures the computer to use the 478907345890734590743 certificate on IP 43.27.89.54, port 443.
.EXAMPLE
Set-SslCertificateBinding -ApplicationID 88d1f8da-aeb5-40a2-a5e5-0e6107825df7 -Thumbprint 4789073458907345907434789073458907345907
Configures the compute to use the 478907345890734590743 certificate as the default certificate on all IP addresses, port 443.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
[OutputType([Carbon.Certificates.SslCertificateBinding])]
param(
[IPAddress]
# The IP address for the binding. Defaults to all IP addresses.
$IPAddress = '0.0.0.0',
[UInt16]
# The port for the binding. Defaults to 443.
$Port = 443,
[Parameter(Mandatory=$true)]
[Guid]
# A unique ID representing the application using the binding. Create your own.
$ApplicationID,
[Parameter(Mandatory=$true)]
[ValidatePattern("^[0-9a-f]{40}$")]
[string]
# The thumbprint of the certificate to use. The certificate must be installed.
$Thumbprint,
[Switch]
# Return a `Carbon.Certificates.SslCertificateBinding` for the configured binding.
$PassThru
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $IPAddress.AddressFamily -eq [Net.Sockets.AddressFamily]::InterNetworkV6 )
{
$ipPort = '[{0}]:{1}' -f $IPAddress,$Port
}
else
{
$ipPort = '{0}:{1}' -f $IPAddress,$Port
}
Remove-SslCertificateBinding -IPAddress $IPAddress -Port $Port
$action = 'creating SSL certificate binding'
if( $pscmdlet.ShouldProcess( $IPPort, $action ) )
{
$appID = $ApplicationID.ToString('B')
Invoke-ConsoleCommand -Target $ipPort -Action $action -ScriptBlock {
netsh http add sslcert ipport=$ipPort certhash=$Thumbprint appid=$appID
}
if( $PassThru )
{
Get-SslCertificateBinding -IPAddress $IPAddress -Port $Port
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Set-TrustedHost
{
<#
.SYNOPSIS
Sets the current computer's trusted hosts list.
.DESCRIPTION
Clears the current trusted hosts list, and sets it to contain only the entries given by the `Entries` parameter.
To clear the trusted hosts list, use `Clear-TrustedHost`.
.LINK
Clear-TrustedHost
.EXAMPLE
Set-TrustedHost -Entry example.com,api.example.com,docs.example.com
Sets the trusted hosts list to contain just the values `example.com`, `api.example.com`, and `docs.example.com`.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string[]]
# An array of trusted host entries.
[Alias("Entries")]
$Entry
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$value = $Entry -join ','
if( $pscmdlet.ShouldProcess( 'trusted hosts', 'set' ) )
{
Set-Item $TrustedHostsPath -Value $Value -Force
}
}
Set-Alias -Name 'Set-TrustedHosts' -Value 'Set-TrustedHost'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Split-Ini
{
<#
.SYNOPSIS
Reads an INI file and returns its contents.
.DESCRIPTION
A configuration file consists of sections, led by a "[section]" header and followed by "name = value" entries:
[spam]
eggs=ham
green=
eggs
[stars]
sneetches = belly
By default, the INI file will be returned as `Carbon.Ini.IniNode` objects for each name/value pair. For example, given the INI file above, the following will be returned:
Line FullName Section Name Value
---- -------- ------- ---- -----
2 spam.eggs spam eggs ham
3 spam.green spam green eggs
7 stars.sneetches stars sneetches belly
It is sometimes useful to get a hashtable back of the name/values. The `AsHashtable` switch will return a hashtable where the keys are the full names of the name/value pairs. For example, given the INI file above, the following hashtable is returned:
Name Value
---- -----
spam.eggs Carbon.Ini.IniNode;
spam.green Carbon.Ini.IniNode;
stars.sneetches Carbon.Ini.IniNode;
}
Each line of an INI file contains one entry. If the lines that follow are indented, they are treated as continuations of that entry. Leading whitespace is removed from values. Empty lines are skipped. Lines beginning with "#" or ";" are ignored and may be used to provide comments.
Configuration keys can be set multiple times, in which case Split-Ini will use the value that was configured last. As an example:
[spam]
eggs=large
ham=serrano
eggs=small
This would set the configuration key named "eggs" to "small".
It is also possible to define a section multiple times. For example:
[foo]
eggs=large
ham=serrano
eggs=small
[bar]
eggs=ham
green=
eggs
[foo]
ham=prosciutto
eggs=medium
bread=toasted
This would set the "eggs", "ham", and "bread" configuration keys of the "foo" section to "medium", "prosciutto", and "toasted", respectively. As you can see, the only thing that matters is the last value that was set for each of the configuration keys.
Be default, operates on the INI file case-insensitively. If your INI is case-sensitive, use the `-CaseSensitive` switch.
.LINK
Set-IniEntry
.LINK
Remove-IniEntry
.EXAMPLE
Split-Ini -Path C:\Users\rspektor\mercurial.ini
Given this INI file:
[ui]
username = Regina Spektor <[email protected]>
[extensions]
share =
extdiff =
`Split-Ini` returns the following objects to the pipeline:
Line FullName Section Name Value
---- -------- ------- ---- -----
2 ui.username ui username Regina Spektor <[email protected]>
5 extensions.share extensions share
6 extensions.extdiff extensions extdiff
.EXAMPLE
Split-Ini -Path C:\Users\rspektor\mercurial.ini -AsHashtable
Given this INI file:
[ui]
username = Regina Spektor <[email protected]>
[extensions]
share =
extdiff =
`Split-Ini` returns the following hashtable:
@{
ui.username = Carbon.Ini.IniNode (
FullName = 'ui.username';
Section = "ui";
Name = "username";
Value = "Regina Spektor <[email protected]>";
LineNumber = 2;
);
extensions.share = Carbon.Ini.IniNode (
FullName = 'extensions.share';
Section = "extensions";
Name = "share"
Value = "";
LineNumber = 5;
)
extensions.extdiff = Carbon.Ini.IniNode (
FullName = 'extensions.extdiff';
Section = "extensions";
Name = "extdiff";
Value = "";
LineNumber = 6;
)
}
.EXAMPLE
Split-Ini -Path C:\Users\rspektor\mercurial.ini -AsHashtable -CaseSensitive
Demonstrates how to parse a case-sensitive INI file.
Given this INI file:
[ui]
username = [email protected]
USERNAME = user2example.com
[UI]
username = [email protected]
`Split-Ini -CaseSensitive` returns the following hashtable:
@{
ui.username = Carbon.Ini.IniNode (
FullName = 'ui.username';
Section = "ui";
Name = "username";
Value = "[email protected]";
LineNumber = 2;
);
ui.USERNAME = Carbon.Ini.IniNode (
FullName = 'ui.USERNAME';
Section = "ui";
Name = "USERNAME";
Value = "[email protected]";
LineNumber = 3;
);
UI.username = Carbon.Ini.IniNode (
FullName = 'UI.username';
Section = "UI";
Name = "username";
Value = "[email protected]";
LineNumber = 6;
);
}
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true,ParameterSetName='ByPath')]
[string]
# The path to the mercurial INI file to read.
$Path,
[Switch]
# Pass each parsed setting down the pipeline instead of collecting them all into a hashtable.
$AsHashtable,
[Switch]
# Parses the INI file in a case-sensitive manner.
$CaseSensitive
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Path $Path -PathType Leaf) )
{
Write-Error ("INI file '{0}' not found." -f $Path)
return
}
$sectionName = ''
$lineNum = 0
$lastSetting = $null
$settings = @{ }
if( $CaseSensitive )
{
$settings = New-Object 'Collections.Hashtable'
}
Get-Content -Path $Path | ForEach-Object {
$lineNum += 1
if( -not $_ -or $_ -match '^[;#]' )
{
if( -not $AsHashtable -and $lastSetting )
{
$lastSetting
}
$lastSetting = $null
return
}
if( $_ -match '^\[([^\]]+)\]' )
{
if( -not $AsHashtable -and $lastSetting )
{
$lastSetting
}
$lastSetting = $null
$sectionName = $matches[1]
Write-Debug "Parsed section [$sectionName]"
return
}
if( $_ -match '^\s+(.*)$' -and $lastSetting )
{
$lastSetting.Value += "`n" + $matches[1]
return
}
if( $_ -match '^([^=]*) ?= ?(.*)$' )
{
if( -not $AsHashtable -and $lastSetting )
{
$lastSetting
}
$name = $matches[1]
$value = $matches[2]
$name = $name.Trim()
$value = $value.TrimStart()
$setting = New-Object Carbon.Ini.IniNode $sectionName,$name,$value,$lineNum
$settings[$setting.FullName] = $setting
$lastSetting = $setting
Write-Debug "Parsed setting '$($setting.FullName)'"
}
}
if( $AsHashtable )
{
return $settings
}
else
{
if( $lastSetting )
{
$lastSetting
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Start-DscPullConfiguration
{
<#
.SYNOPSIS
Performs a configuration check on a computer that is using DSC's Pull refresh mode.
.DESCRIPTION
The most frequently a computer's LCM will download new configuration is every 15 minutes; the most frequently it will apply it is every 30 minutes. This function contacts a computer's LCM and tells it to apply and download its configuration immediately.
If a computer's LCM isn't configured to pull its configuration, an error is written, and nothing happens.
If a configuration check fails, the errors are retrieved from the computer's event log and written out as errors. The `Remote Event Log Management` firewall rules must be enabled on the computer for this to work. If they aren't, you'll see an error explaining this. The `Get-DscError` help topic shows how to enable these firewall rules.
Sometimes, the LCM does a really crappy job of updating to the latest version of a module. `Start-DscPullConfiguration` will delete modules on the target computers. Specify the names of the modules to delete with the `ModuleName` parameter. Make sure you only delete modules that will get installed by the LCM. Only modules installed in the `$env:ProgramFiles\WindowsPowerShell\Modules` directory are removed.
`Start-DscPullConfiguration` is new in Carbon 2.0.
.LINK
Get-DscError
.LINK
Initialize-Lcm
.LINK
Get-DscWinEvent
.EXAMPLE
Start-DscPullConfiguration -ComputerName '10.1.2.3','10.4.5.6'
Demonstrates how to immedately download and apply a computer from its pull server.
.EXAMPLE
Start-DscPullConfiguration -ComputerName '10.1.2.3' -Credential (Get-Credential domain\username)
Demonstrates how to use custom credentials to contact the remote server.
.EXAMPLE
Start-DscPullConfiguration -CimSession $session
Demonstrates how to use one or more CIM sessions to invoke a configuration check.
.EXAMPLE
Start-DScPullConfiguration -ComputerName 'example.com' -ModuleName 'Carbon'
Demonstrates how to delete modules on the target computers, because sometimes the LCM does a really crappy job of it.
#>
[CmdletBinding(DefaultParameterSetName='WithCredentials')]
param(
[Parameter(Mandatory=$true,ParameterSetName='WithCredentials')]
[string[]]
# The credential to use when connecting to the target computer.
$ComputerName,
[Parameter(ParameterSetName='WithCredentials')]
[PSCredential]
# The credentials to use when connecting to the computers.
$Credential,
[Parameter(ParameterSetName='WithCimSession')]
[Microsoft.Management.Infrastructure.CimSession[]]
$CimSession,
[string[]]
# Any modules that should be removed from the target computer's PSModulePath (since the LCM does a *really* crappy job of removing them).
$ModuleName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$credentialParam = @{ }
if( $PSCmdlet.ParameterSetName -eq 'WithCredentials' )
{
if( $Credential )
{
$credentialParam.Credential = $Credential
}
$CimSession = New-CimSession -ComputerName $ComputerName @credentialParam
if( -not $CimSession )
{
return
}
}
$CimSession = Get-DscLocalConfigurationManager -CimSession $CimSession |
ForEach-Object {
if( $_.RefreshMode -ne 'Pull' )
{
Write-Error ('The Local Configuration Manager on ''{0}'' is not in Pull mode (current RefreshMode is ''{1}'').' -f $_.PSComputerName,$_.RefreshMode)
return
}
foreach( $session in $CimSession )
{
if( $session.ComputerName -eq $_.PSComputerName )
{
return $session
}
}
}
if( -not $CimSession )
{
return
}
# Get rid of any _tmp directories you might find out there.
Invoke-Command -ComputerName $CimSession.ComputerName @credentialParam -ScriptBlock {
$modulesRoot = Join-Path -Path $env:ProgramFiles -ChildPath 'WindowsPowerShell\Modules'
Get-ChildItem -Path $modulesRoot -Filter '*_tmp' -Directory |
Remove-Item -Recurse
}
if( $ModuleName )
{
# Now, get rid of any modules we know will need to get updated
Invoke-Command -ComputerName $CimSession.ComputerName @credentialParam -ScriptBlock {
param(
[string[]]
$ModuleName
)
$dscProcessID = Get-WmiObject msft_providers |
Where-Object {$_.provider -like 'dsccore'} |
Select-Object -ExpandProperty HostProcessIdentifier
Stop-Process -Id $dscProcessID -Force
$modulesRoot = Join-Path -Path $env:ProgramFiles -ChildPath 'WindowsPowerShell\Modules'
Get-ChildItem -Path $modulesRoot -Directory |
Where-Object { $ModuleName -contains $_.Name } |
Remove-Item -Recurse
} -ArgumentList (,$ModuleName)
}
# Getting the date/time on the remote computers so we can get errors later.
$win32OS = Get-CimInstance -CimSession $CimSession -ClassName 'Win32_OperatingSystem'
$results = Invoke-CimMethod -CimSession $CimSession `
-Namespace 'root/microsoft/windows/desiredstateconfiguration' `
-Class 'MSFT_DscLocalConfigurationManager' `
-MethodName 'PerformRequiredConfigurationChecks' `
-Arguments @{ 'Flags' = [uint32]1 }
$successfulComputers = $results | Where-Object { $_ -and $_.ReturnValue -eq 0 } | Select-Object -ExpandProperty 'PSComputerName'
$CimSession |
Where-Object { $successfulComputers -notcontains $_.ComputerName } |
ForEach-Object {
$session = $_
$startedAt= $win32OS | Where-Object { $_.PSComputerName -eq $session.ComputerName } | Select-Object -ExpandProperty 'LocalDateTime'
Get-DscError -ComputerName $session.ComputerName -StartTime $startedAt -Wait
} |
Write-DscError
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-AdminPrivilege
{
<#
.SYNOPSIS
Checks if the current user is an administrator or has administrative privileges.
.DESCRIPTION
Many tools, cmdlets, and APIs require administative privileges. Use this function to check. Returns `True` if the current user has administrative privileges, or `False` if he doesn't. Or she. Or it.
This function handles UAC and computers where UAC is disabled.
.EXAMPLE
Test-AdminPrivilege
Returns `True` if the current user has administrative privileges, or `False` if the user doesn't.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
Write-Debug -Message "Checking if current user '$($identity.Name)' has administrative privileges."
$hasElevatedPermissions = $false
foreach ( $group in $identity.Groups )
{
if ( $group.IsValidTargetType([Security.Principal.SecurityIdentifier]) )
{
$groupSid = $group.Translate([Security.Principal.SecurityIdentifier])
if ( $groupSid.IsWellKnown("AccountAdministratorSid") -or $groupSid.IsWellKnown("BuiltinAdministratorsSid"))
{
return $true
}
}
}
return $false
}
Set-Alias -Name 'Test-AdminPrivileges' -Value 'Test-AdminPrivilege'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-DotNet
{
<#
.SYNOPSIS
Tests if .NET is installed.
.DESCRIPTION
Currently, this function only tests if .NET 2 or 4 is installed. Perhaps some friendly people out there will extend it to perform further checks?
.LINK
http://msdn.microsoft.com/en-us/kb/kbarticle.aspx?id=318785
.EXAMPLE
Test-DotNet -v2
Demonstrates how to test if .NET 2 is installed.
.EXAMPLE
Test-DotNet -v4 -Full
Demonstrates how to test if the full .NET v4 is installed.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,ParameterSetName='v2')]
[Switch]
# Test if .NET 2.0 is installed.
$V2,
[Parameter(Mandatory=$true,ParameterSetName='v4Client')]
[Parameter(Mandatory=$true,ParameterSetName='v4Full')]
[Switch]
# Test if .NET 4.0 is installed.
$V4,
[Parameter(Mandatory=$true,ParameterSetName='v4Client')]
[Switch]
# Test if hte .NET 4 client profile is installed.
$Client,
[Parameter(Mandatory=$true,ParameterSetName='v4Full')]
[Switch]
# Test if the .NET 4 full profile is installed.
$Full
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$runtimeSetupRegPath = switch( $PSCmdlet.ParameterSetName )
{
'v2' { 'hklm:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727' }
'v4Client' { 'hklm:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client' }
'v4Full' { 'hklm:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' }
default { Write-Error ('Unknown parameter set ''{0}''.' -f $PSCmdlet.ParameterSetName) }
}
if( -not $runtimeSetupRegPath )
{
return
}
if( -not (Test-RegistryKeyValue -Path $runtimeSetupRegPath -Name 'Install') )
{
return $false
}
$value = Get-RegistryKeyValue -Path $runtimeSetupRegPath -Name 'Install'
return ($value -eq 1)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-DscTargetResource
{
<#
.SYNOPSIS
Tests that all the properties on a resource and object are the same.
.DESCRIPTION
DSC expects a resource's `Test-TargetResource` function to return `$false` if an object needs to be updated. Usually, you compare the current state of a resource with the desired state, and return `$false` if anything doesn't match.
This function takes in a hashtable of the current resource's state (what's returned by `Get-TargetResource`) and compares it to the desired state (the values passed to `Test-TargetResource`). If any property in the target resource is different than the desired resource, a list of stale resources is written to the verbose stream and `$false` is returned.
Here's a quick example:
return Test-TargetResource -TargetResource (Get-TargetResource -Name 'fubar') -DesiredResource $PSBoundParameters -Target ('my resource ''fubar''')
If you want to exclude properties from the evaluation, just remove them from the hashtable returned by `Get-TargetResource`:
$resource = Get-TargetResource -Name 'fubar'
$resource.Remove( 'PropertyThatDoesNotMatter' )
return Test-TargetResource -TargetResource $resource -DesiredResource $PSBoundParameters -Target ('my resource ''fubar''')
`Test-DscTargetResource` is new in Carbon 2.0.
.OUTPUTS
System.Boolean.
.EXAMPLE
Test-TargetResource -TargetResource (Get-TargetResource -Name 'fubar') -DesiredResource $PSBoundParameters -Target ('my resource ''fubar''')
Demonstrates how to test that all the properties on a DSC resource are the same was what's desired.
#>
[CmdletBinding()]
[OutputType([bool])]
param(
[Parameter(Mandatory=$true)]
[hashtable]
# The current state of the resource.
$TargetResource,
[Parameter(Mandatory=$true)]
[hashtable]
# The desired state of the resource. Properties not in this hashtable are skipped. Usually you'll pass `PSBoundParameters` from your `Test-TargetResource` function.
$DesiredResource,
[Parameter(Mandatory=$true)]
[string]
# The a description of the target object being tested. Output in verbose messages.
$Target
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$notEqualProperties = $TargetResource.Keys |
Where-Object { $_ -ne 'Ensure' } |
Where-Object { $DesiredResource.ContainsKey( $_ ) } |
Where-Object {
$desiredObj = $DesiredResource[$_]
$targetObj = $TargetResource[$_]
if( $desiredobj -eq $null -or $targetObj -eq $null )
{
return ($desiredObj -ne $targetObj)
}
if( -not $desiredObj.GetType().IsArray -or -not $targetObj.GetType().IsArray )
{
return ($desiredObj -ne $targetObj)
}
if( $desiredObj.Length -ne $targetObj.Length )
{
return $true
}
$desiredObj | Where-Object { $targetObj -notcontains $_ }
}
if( $notEqualProperties )
{
Write-Verbose ('{0} has stale properties: ''{1}''' -f $Target,($notEqualProperties -join ''','''))
return $false
}
return $true
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-FirewallStatefulFtp
{
<#
.SYNOPSIS
Tests if the firewall's `StatefulFtp` setting is enabled.
.DESCRIPTION
Returns `True` if the firewall's `StatefulFtp` setting is enabled, `False` otherwise.
If the firewall isn't configurable, writes an error and returns nothing, which will probably be interpreted by your script as `False`. Can't help you there. At least you'll get an error message.
.OUTPUTS
System.Boolean.
.LINK
Assert-FirewallConfigurable
.EXAMPLE
Test-FirewallStatefulFtp
Returns `True` if the firewall's `StatefulFtp` setting is enabled, `False` otherwise.
#>
[CmdletBinding()]
param()
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Assert-FirewallConfigurable) )
{
return
}
$output = netsh advfirewall show global StatefulFtp
$line = $output[3]
return $line -match 'Enable'
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-Group
{
<#
.SYNOPSIS
Checks if a *local* group exists.
.DESCRIPTION
Uses .NET's AccountManagement API to check if a *local* group exists. Returns `True` if the *local* account exists, or `False` if it doesn't.
.OUTPUTS
System.Boolean
.LINK
Get-Group
.LINK
Install-Group
.LINK
Uninstall-Group
.EXAMPLE
Test-Group -Name RebelAlliance
Checks if the `RebelAlliance` *local* group exists. Returns `True` if it does, `False` if it doesn't.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the *local* group to check.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$ctx = New-Object 'DirectoryServices.AccountManagement.PrincipalContext' ([DirectoryServices.AccountManagement.ContextType]::Machine)
$group = [DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity( $ctx, $Name )
try
{
if( $group )
{
$group.Dispose()
return $true
}
else
{
return $false
}
}
finally
{
$ctx.Dispose()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-GroupMember
{
<#
.SYNOPSIS
Tests if a user or group is a member of a *local* group.
.DESCRIPTION
The `Test-GroupMember` function tests if a user or group is a member of a *local* group using [.NET's DirectoryServices.AccountManagement APIs](https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement.aspx). If the group or member you want to check don't exist, you'll get errors and `$null` will be returned. If `Member` is in the group, `$true` is returned. If `Member` is not in the group, `$false` is returned.
The user running this function must have permission to access whatever directory the `Member` is in and whatever directory current members of the group are in.
This function was added in Carbon 2.1.0.
.LINK
Add-GroupMember
.LINK
Install-Group
.LINK
Remove-GroupMember
.LINK
Test-Group
.LINK
Uninstall-Group
.EXAMPLE
Test-GroupMember -GroupName 'SithLords' -Member 'REBELS\LSkywalker'
Demonstrates how to test if a user is a member of a group. In this case, it tests if `REBELS\LSkywalker` is in the local `SithLords`, *which obviously he isn't*, so `$false` is returned.
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]
# The name of the group whose membership is being tested.
$GroupName,
[Parameter(Mandatory=$true)]
[string]
# The name of the member to check.
$Member
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Group -Name $GroupName) )
{
Write-Error -Message ('Group ''{0}'' not found.' -f $GroupName)
return
}
$group = Get-Group -Name $GroupName
if( -not $group )
{
return
}
$principal = Resolve-Identity -Name $Member
if( -not $principal )
{
return
}
try
{
return $principal.IsMemberOfLocalGroup($group.Name)
}
catch
{
Write-Error -Message ('Checking if ''{0}'' is a member of local group ''{1}'' failed: {2}' -f $principal.FullName,$group.Name,$_)
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-Identity
{
<#
.SYNOPSIS
Tests that a name is a valid Windows local or domain user/group.
.DESCRIPTION
Uses the Windows `LookupAccountName` function to find an identity. If it can't be found, returns `$false`. Otherwise, it returns `$true`.
Use the `PassThru` switch to return a `Carbon.Identity` object (instead of `$true` if the identity exists.
.LINK
Resolve-Identity
.LINK
Resolve-IdentityName
.EXAMPLE
Test-Identity -Name 'Administrators
Tests that a user or group called `Administrators` exists on the local computer.
.EXAMPLE
Test-Identity -Name 'CARBON\Testers'
Tests that a group called `Testers` exists in the `CARBON` domain.
.EXAMPLE
Test-Identity -Name 'Tester' -PassThru
Tests that a user or group named `Tester` exists and returns a `System.Security.Principal.SecurityIdentifier` object if it does.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the identity to test.
$Name,
[Switch]
# Returns a `Carbon.Identity` object if the identity exists.
$PassThru
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$identity = [Carbon.Identity]::FindByName( $Name )
if( -not $identity )
{
return $false
}
if( $PassThru )
{
return $identity
}
return $true
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-IisAppPool
{
<#
.SYNOPSIS
Checks if an app pool exists.
.DESCRIPTION
Returns `True` if an app pool with `Name` exists. `False` if it doesn't exist.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Test-IisAppPool -Name Peanuts
Returns `True` if the Peanuts app pool exists, `False` if it doesn't.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the app pool.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$appPool = Get-IisAppPool -Name $Name
if( $appPool )
{
return $true
}
return $false
}
Set-Alias -Name 'Test-IisAppPoolExists' -Value 'Test-IisAppPool'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-IisConfigurationSection
{
<#
.SYNOPSIS
Tests a configuration section.
.DESCRIPTION
You can test if a configuration section exists or wheter it is locked.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.OUTPUTS
System.Boolean.
.EXAMPLE
Test-IisConfigurationSection -SectionPath 'system.webServer/I/Do/Not/Exist'
Tests if a configuration section exists. Returns `False`, because the given configuration section doesn't exist.
.EXAMPLE
Test-IisConfigurationSection -SectionPath 'system.webServer/cgi' -Locked
Returns `True` if the global CGI section is locked. Otherwise `False`.
.EXAMPLE
Test-IisConfigurationSection -SectionPath 'system.webServer/security/authentication/basicAuthentication' -SiteName `Peanuts` -VirtualPath 'SopwithCamel' -Locked
Returns `True` if the `Peanuts` website's `SopwithCamel` sub-directory's `basicAuthentication` security authentication section is locked. Otherwise, returns `False`.
#>
[CmdletBinding(DefaultParameterSetName='CheckExists')]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to the section to test.
$SectionPath,
[Parameter()]
[string]
# The name of the site whose configuration section to test. Optional. The default is the global configuration.
$SiteName,
[Parameter()]
[Alias('Path')]
[string]
# The optional path under `SiteName` whose configuration section to test.
$VirtualPath,
[Parameter(Mandatory=$true,ParameterSetName='CheckLocked')]
[Switch]
# Test if the configuration section is locked.
$Locked
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$getArgs = @{
SectionPath = $SectionPath;
}
if( $SiteName )
{
$getArgs.SiteName = $SiteName
}
if( $VirtualPath )
{
$getArgs.VirtualPath = $VirtualPath
}
$section = Get-IisConfigurationSection @getArgs -ErrorAction SilentlyContinue
if( $pscmdlet.ParameterSetName -eq 'CheckExists' )
{
if( $section )
{
return $true
}
else
{
return $false
}
}
if( -not $section )
{
Write-Error ('IIS:{0}: section {1} not found.' -f (Join-IisVirtualPath $SiteName $VirtualPath),$SectionPath)
return
}
if( $pscmdlet.ParameterSetName -eq 'CheckLocked' )
{
return $section.OverrideMode -eq 'Deny'
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-IisSecurityAuthentication
{
<#
.SYNOPSIS
Tests if IIS authentication types are enabled or disabled on a site and/or virtual directory under that site.
.DESCRIPTION
You can check if anonymous, basic, or Windows authentication are enabled. There are switches for each authentication type.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.OUTPUTS
System.Boolean.
.EXAMPLE
Test-IisSecurityAuthentication -SiteName Peanuts -Anonymous
Returns `true` if anonymous authentication is enabled for the `Peanuts` site. `False` if it isn't.
.EXAMPLE
Test-IisSecurityAuthentication -SiteName Peanuts -VirtualPath Doghouse -Basic
Returns `true` if basic authentication is enabled for`Doghouse` directory under the `Peanuts` site. `False` if it isn't.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The site where anonymous authentication should be set.
$SiteName,
[Alias('Path')]
[string]
# The optional path where anonymous authentication should be set.
$VirtualPath = '',
[Parameter(Mandatory=$true,ParameterSetName='Anonymous')]
[Switch]
# Tests if anonymous authentication is enabled.
$Anonymous,
[Parameter(Mandatory=$true,ParameterSetName='Basic')]
[Switch]
# Tests if basic authentication is enabled.
$Basic,
[Parameter(Mandatory=$true,ParameterSetName='Digest')]
[Switch]
# Tests if digest authentication is enabled.
$Digest,
[Parameter(Mandatory=$true,ParameterSetName='Windows')]
[Switch]
# Tests if Windows authentication is enabled.
$Windows
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$getConfigArgs = @{ $pscmdlet.ParameterSetName = $true }
$authSettings = Get-IisSecurityAuthentication -SiteName $SiteName -VirtualPath $VirtualPath @getConfigArgs
return ($authSettings.GetAttributeValue('enabled') -eq 'true')
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-IisWebsite
{
<#
.SYNOPSIS
Tests if a website exists.
.DESCRIPTION
Returns `True` if a website with name `Name` exists. `False` if it doesn't.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Test-IisWebsite -Name 'Peanuts'
Returns `True` if the `Peanuts` website exists. `False` if it doesn't.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the website whose existence to check.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$manager = New-Object 'Microsoft.Web.Administration.ServerManager'
try
{
$site = $manager.Sites | Where-Object { $_.Name -eq $Name }
if( $site )
{
return $true
}
return $false
}
finally
{
$manager.Dispose()
}
}
Set-Alias -Name Test-IisWebsiteExists -Value Test-IisWebsite
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-IPAddress
{
<#
.SYNOPSIS
Tests that an IP address is in use on the local computer.
.DESCRIPTION
Sometimes its useful to know if an IP address is being used on the local computer. This function does just that.
.LINK
Test-IPAddress
.EXAMPLE
Test-IPAddress -IPAddress '10.1.2.3'
Returns `true` if the IP address `10.1.2.3` is being used on the local computer.
.EXAMPLE
Test-IPAddress -IPAddress '::1'
Demonstrates that you can use IPv6 addresses.
.EXAMPLE
Test-IPAddress -IPAddress ([Net.IPAddress]::Parse('10.5.6.7'))
Demonstrates that you can use real `System.Net.IPAddress` objects.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Net.IPAddress]
# The IP address to check.
$IPAddress
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$ip = Get-IPAddress | Where-Object { $_ -eq $IPAddress }
if( $ip )
{
return $true
}
else
{
return $false
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-NtfsCompression
{
<#
.SYNOPSIS
Tests if NTFS compression is turned on.
.DESCRIPTION
Returns `$true` if compression is enabled, `$false` otherwise.
.LINK
Disable-NtfsCompression
.LINK
Enable-NtfsCompression
.EXAMPLE
Test-NtfsCompression -Path C:\Projects\Carbon
Returns `$true` if NTFS compression is enabled on `C:\Projects\CArbon`. If it is disabled, returns `$false`.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The path where compression should be enabled.
$Path
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Path -Path $Path) )
{
Write-Error ('Path {0} not found.' -f $Path)
return
}
$attributes = Get-Item -Path $Path -Force | Select-Object -ExpandProperty Attributes
if( $attributes )
{
return (($attributes -band [IO.FileAttributes]::Compressed) -eq [IO.FileAttributes]::Compressed)
}
return $false
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-OSIs32Bit
{
<#
.SYNOPSIS
Tests if the current operating system is 32-bit.
.DESCRIPTION
Regardless of the bitness of the currently running process, returns `True` if the current OS is a 32-bit OS.
.OUTPUTS
System.Boolean.
.LINK
http://msdn.microsoft.com/en-us/library/system.environment.is64bitoperatingsystem.aspx
.EXAMPLE
Test-OSIs32Bit
Returns `True` if the current operating system is 32-bit, and `False` otherwise.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
return -not (Test-OSIs64Bit)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-OSIs64Bit
{
<#
.SYNOPSIS
Tests if the current operating system is 64-bit.
.DESCRIPTION
Regardless of the bitness of the currently running process, returns `True` if the current OS is a 64-bit OS.
.OUTPUTS
System.Boolean.
.LINK
http://msdn.microsoft.com/en-us/library/system.environment.is64bitoperatingsystem.aspx
.EXAMPLE
Test-OSIs64Bit
Returns `True` if the current operating system is 64-bit, and `False` otherwise.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
return ([Environment]::Is64BitOperatingSystem)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-PathIsJunction
{
<#
.SYNOPSIS
Tests if a path is a junction.
.DESCRIPTION
The `Test-PathIsJunction` function tests if path is a junction (i.e. reparse point). If the path doesn't exist, returns `$false`.
Carbon adds an `IsJunction` extension method on `DirectoryInfo` objects, which you can use instead e.g.
Get-ChildItem -Path $env:Temp |
Where-Object { $_.PsIsContainer -and $_.IsJunction }
would return all the junctions under the current user's temporary directory.
The `LiteralPath` parameter was added in Carbon 2.2.0. Use it to check paths that contain wildcard characters.
.EXAMPLE
Test-PathIsJunction -Path C:\I\Am\A\Junction
Returns `$true`.
.EXAMPLE
Test-PathIsJunction -Path C:\I\Am\Not\A\Junction
Returns `$false`.
.EXAMPLE
Get-ChildItem * | Where-Object { $_.PsIsContainer -and $_.IsJunction }
Demonstrates an alternative way of testing for junctions. Uses Carbon's `IsJunction` extension method on the `DirectoryInfo` type to check if any directories under the current directory are junctions.
.EXAMPLE
Test-PathIsJunction -LiteralPath 'C:\PathWithWildcards[]'
Demonstrates how to test if a path with wildcards is a junction.
#>
[CmdletBinding(DefaultParameterSetName='Path')]
param(
[Parameter(Mandatory=$true,ParameterSetName='Path',Position=0)]
[string]
# The path to check. Wildcards allowed. If using wildcards, returns `$true` if all paths that match the wildcard are junctions. Otherwise, return `$false`.
$Path,
[Parameter(Mandatory=$true,ParameterSetName='LiteralPath')]
[string]
# The literal path to check. Use this parameter to test a path that contains wildcard characters.
#
# This parameter was added in Carbon 2.2.0.
$LiteralPath
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSCmdlet.ParameterSetName -eq 'Path' )
{
if( [Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Path) )
{
$junctions = Get-Item -Path $Path -Force |
Where-Object { $_.PsIsContainer -and $_.IsJunction }
return ($junctions -ne $null)
}
return Test-PathIsJunction -LiteralPath $Path
}
if( Test-Path -LiteralPath $LiteralPath -PathType Container )
{
return (Get-Item -LiteralPath $LiteralPath -Force).IsJunction
}
return $false
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-PerformanceCounter
{
<#
.SYNOPSIS
Tests if a performance counter exists.
.DESCRIPTION
Returns `True` if counter `Name` exists in category `CategoryName`. `False` if it does not exist or the category doesn't exist.
.EXAMPLE
Test-PerformanceCounter -CategoryName 'ToyotaCamry' -Name 'MilesPerGallon'
Returns `True` if the `ToyotaCamry` performance counter category has a `MilesPerGallon` counter. `False` if the counter doesn't exist.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The category's name where the performance counter exists. Or might exist. As the case may be.
$CategoryName,
[Parameter(Mandatory=$true)]
[string]
# The performance counter's name.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( (Test-PerformanceCounterCategory -CategoryName $CategoryName) )
{
return [Diagnostics.PerformanceCounterCategory]::CounterExists( $Name, $CategoryName )
}
return $false
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-PerformanceCounterCategory
{
<#
.SYNOPSIS
Tests if a performance counter category exists.
.DESCRIPTION
Returns `True` if category `CategoryName` exists. `False` if it does not exist.
.EXAMPLE
Test-PerformanceCounterCategory -CategoryName 'ToyotaCamry'
Returns `True` if the `ToyotaCamry` performance counter category exists. `False` if the category doesn't exist.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the cateogry whose existence to check.
$CategoryName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
return [Diagnostics.PerformanceCounterCategory]::Exists( $CategoryName )
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-PowerShellIs32Bit
{
<#
.SYNOPSIS
Tests if the current PowerShell process is 32-bit.
.DESCRIPTION
Returns `True` if the currently executing PowerShell process is 32-bit/x86, `False` if it is 64-bit/x64.
.OUTPUTS
System.Boolean.
.LINK
http://msdn.microsoft.com/en-us/library/system.environment.is64bitprocess.aspx
.EXAMPLE
Test-PowerShellIs32Bit
Returns `True` if PowerShell is 32-bit/x86, `False` if it is 64-bit/x64.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
return -not (Test-PowerShellIs64Bit)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-PowerShellIs64Bit
{
<#
.SYNOPSIS
Tests if the current PowerShell process is 64-bit/x64.
.DESCRIPTION
Returns `True` if the currently executing PowerShell process is 64-bit/x64, `False` if it is 32-bit/x86.
.OUTPUTS
System.Boolean.
.LINK
http://msdn.microsoft.com/en-us/library/system.environment.is64bitprocess.aspx
.EXAMPLE
Test-PowerShellIs64Bit
Returns `True` if PowerShell is 64-bit/x64, `False` if it is 32-bit/x86.
#>
[CmdletBinding()]
param(
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
return ([Environment]::Is64BitProcess)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-Privilege
{
<#
.SYNOPSIS
Tests if an identity has a given privilege.
.DESCRIPTION
Returns `true` if an identity has a privilege. `False` otherwise.
.LINK
Carbon_Privilege
.LINK
Get-Privilege
.LINK
Grant-Privilege
.LINK
Revoke-Privilege
.EXAMPLE
Test-Privilege -Identity Forrester -Privilege SeServiceLogonRight
Tests if `Forrester` has the `SeServiceLogonRight` privilege.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The identity whose privileges to check.
$Identity,
[Parameter(Mandatory=$true)]
[string]
# The privilege to check.
$Privilege
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$matchingPrivilege = Get-Privilege -Identity $Identity |
Where-Object { $_ -eq $Privilege }
return ($matchingPrivilege -ne $null)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-RegistryKeyValue
{
<#
.SYNOPSIS
Tests if a registry value exists.
.DESCRIPTION
The usual ways for checking if a registry value exists don't handle when a value simply has an empty or null value. This function actually checks if a key has a value with a given name.
.EXAMPLE
Test-RegistryKeyValue -Path 'hklm:\Software\Carbon\Test' -Name 'Title'
Returns `True` if `hklm:\Software\Carbon\Test` contains a value named 'Title'. `False` otherwise.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to the registry key where the value should be set. Will be created if it doesn't exist.
$Path,
[Parameter(Mandatory=$true)]
[string]
# The name of the value being set.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Path -Path $Path -PathType Container) )
{
return $false
}
$properties = Get-ItemProperty -Path $Path
if( -not $properties )
{
return $false
}
$member = Get-Member -InputObject $properties -Name $Name
if( $member )
{
return $true
}
else
{
return $false
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-ScheduledTask
{
<#
.SYNOPSIS
Tests if a scheduled task exists on the current computer.
.DESCRIPTION
The `Test-ScheduledTask` function uses `schtasks.exe` to tests if a task with a given name exists on the current computer. If it does, `$true` is returned. Otherwise, `$false` is returned. This name must be the *full task name*, i.e. the task's path/location and its name.
.LINK
Get-ScheduledTask
.EXAMPLE
Test-ScheduledTask -Name 'AutoUpdateMyApp'
Demonstrates how to test if a scheduled tasks exists.
#>
[CmdletBinding()]
[OutputType([bool])]
param(
[Parameter()]
[Alias('TaskName')]
[string]
# The name of the scheduled task to check. This must be the *full task name*, i.e. the task's path/location and its name.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$Name = Join-Path -Path '\' -ChildPath $Name
$task = schtasks /query /fo csv 2> $null | ConvertFrom-Csv | Where-Object { $_.TaskName -eq $Name }
if( $task )
{
return $true
}
else
{
return $false
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-Service
{
<#
.SYNOPSIS
Tests if a service exists, without writing anything out to the error stream.
.DESCRIPTION
`Get-Service` writes an error when a service doesn't exist. This function tests if a service exists without writing anyting to the output stream.
.OUTPUTS
System.Boolean.
.LINK
Carbon_Service
.LINK
Install-Service
.LINK
Uninstall-Service
.EXAMPLE
Test-Service -Name 'Drive'
Returns `true` if the `Drive` service exists. `False` otherwise.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the service to test.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$service = Get-Service -Name "$Name*" |
Where-Object { $_.Name -eq $Name }
if( $service )
{
return $true
}
else
{
return $false
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-SslCertificateBinding
{
<#
.SYNOPSIS
Tests if an SSL certificate binding exists.
.DESCRIPTION
SSL certificates are bound to IP addresses and ports. This function tests if one exists on a given IP address/port.
.EXAMPLE
Test-SslCertificateBinding -Port 443
Tests if there is a default SSL certificate bound to all a machine's IP addresses on port 443.
.EXAMPLE
Test-SslCertificateBinding -IPAddress 10.0.1.1 -Port 443
Tests if there is an SSL certificate bound to IP address 10.0.1.1 on port 443.
.EXAMPLE
Test-SslCertificateBinding
Tests if there are any SSL certificates bound to any IP address/port on the machine.
#>
[CmdletBinding()]
param(
[IPAddress]
# The IP address to test for an SSL certificate.
$IPAddress,
[Uint16]
# The port to test for an SSL certificate.
$Port
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$getArgs = @{ }
if( $IPAddress )
{
$getArgs.IPAddress = $IPAddress
}
if( $Port )
{
$getArgs.Port = $Port
}
$binding = Get-SslCertificateBinding @getArgs
if( $binding )
{
return $True
}
else
{
return $False
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-TypeDataMember
{
<#
.SYNOPSIS
Tests if a type has an extended type member defined.
.DESCRIPTION
`Test-TypeDataMember` tests if a type has an extended type member defined. If the type isn't found, you'll get an error.
Returns `$true` if the type is found and the member is defined. Otherwise, returns `$false`.
This function is new in Carbon 2.0.
.EXAMPLE
Test-TypeDataMember -TypeName 'Microsoft.Web.Administration.Site' -MemberName 'PhysicalPath'
Tests if the `Microsoft.Web.Administration.Site` type has a `PhysicalPath` extended type member defined.
#>
[CmdletBinding()]
[OutputType([bool])]
param(
[Parameter(Mandatory=$true)]
[string]
# The type name to check.
$TypeName,
[Parameter(Mandatory=$true)]
[string]
# The name of the member to check.
$MemberName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$typeData = Get-TypeData -TypeName $TypeName
if( -not $typeData )
{
# The type isn't defined or there is no extended type data on it.
return $false
}
return $typeData.Members.ContainsKey( $MemberName )
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-UncPath
{
<#
.SYNOPSIS
Tests if a path is a UNC path.
.DESCRIPTION
Converts the path to a URI and returns the value of its `IsUnc` property.
This function does not test if path exists. Use `Test-Path` for that.
.LINK
Test-Path
.LINK
http://blogs.microsoft.co.il/blogs/ScriptFanatic//archive/2010/05/27/quicktip-how-to-validate-a-unc-path.aspx
.EXAMPLE
Test-UncPath -Path '\\computer\share'
Returns `true` since `\\computer\share` is a UNC path. Note that `Test-UncPath` does not have to exist.
.EXAMPLE
Test-UncPath -Path 'C:\Windows'
Returns `false` since `C:\Windows` is not a UNC path.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to test/check.
$Path
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
([Uri]$Path).IsUnc
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-User
{
<#
.SYNOPSIS
Checks if a *local* user account exists.
.DESCRIPTION
Uses .NET's AccountManagement API to check if a *local* user account exists. Returns `True` if the *local* account exists, or `False` if it doesn't.
.OUTPUTS
System.Boolean
.LINK
Get-User
.LINK
Install-User
.LINK
Uninstall-User
.EXAMPLE
Test-User -Username HSolo
Checks if the HSolo *local* account exists. Returns `True` if it does, `False` if it doesn't or its encased in carbonite.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[ValidateLength(1,20)]
[string]
# The username of the *local* account to check
$Username
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$ctx = New-Object 'DirectoryServices.AccountManagement.PrincipalContext' ([DirectoryServices.AccountManagement.ContextType]::Machine)
$user = [DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity( $ctx, $Username )
if( $user )
{
return $true
}
else
{
try
{
return $false
}
finally
{
$ctx.Dispose()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-WindowsFeature
{
<#
.SYNOPSIS
Tests if an optional Windows component exists and, optionally, if it is installed.
.DESCRIPTION
Feature names are different across different versions of Windows. This function tests if a given feature exists. You can also test if a feature is installed by setting the `Installed` switch.
Feature names are case-sensitive and are different between different versions of Windows. For a list, on Windows 2008, run `serveramanagercmd.exe -q`; on Windows 7, run `Get-WmiObject -Class Win32_OptionalFeature | Select-Object Name`. On Windows 8/2012, use `Get-WindowsFeature`.
.LINK
Get-WindowsFeature
.LINK
Install-WindowsFeature
.LINK
Uninstall-WindowsFeature
.EXAMPLE
Test-WindowsFeature -Name MSMQ-Server
Tests if the MSMQ-Server feature exists on the current computer.
.EXAMPLE
Test-WindowsFeature -Name IIS-WebServer -Installed
Tests if the IIS-WebServer features exists and is installed/enabled.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the feature to test. Feature names are case-sensitive and are different between different versions of Windows. For a list, on Windows 2008, run `serveramanagercmd.exe -q`; on Windows 7, run `Get-WmiObject -Class Win32_OptionalFeature | Select-Object Name`. On Windows 8/2012, use `Get-WindowsFeature`.
$Name,
[Switch]
# Test if the service is installed in addition to if it exists.
$Installed
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Get-Module -Name 'ServerManager') -and -not (Assert-WindowsFeatureFunctionsSupported) )
{
return
}
$feature = Get-WindowsFeature -Name $Name
if( $feature )
{
if( $Installed )
{
return $feature.Installed
}
return $true
}
else
{
return $false
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Test-ZipFile
{
<#
.SYNOPSIS
Tests if a file is a ZIP file using the `DotNetZip` library.
.DESCRIPTION
Uses the `Ionic.Zip.ZipFile.IsZipFile` static method to determine if a file is a ZIP file. The file *must* exist. If it doesn't, an error is written and `$null` is returned.
You can pipe `System.IO.FileInfo` (or strings) to this function to filter multiple items.
.LINK
https://www.nuget.org/packages/DotNetZip
.LINK
Compress-Item
.LINK
Expand-Item
.EXAMPLE
Test-ZipFile -Path 'MyCoolZip.zip'
Demonstrates how to check the current directory if MyCoolZip.zip is really a ZIP file.
#>
[OutputType([bool])]
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Alias('FullName')]
[string]
# The path to the file to test.
$Path
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$Path = Resolve-FullPath -Path $Path
if( -not (Test-Path -Path $Path -PathType Leaf) )
{
Write-Error ('File ''{0}'' not found.' -f $Path)
return
}
return [Ionic.Zip.ZipFile]::IsZipFile( $Path )
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Uninstall-Certificate
{
<#
.SYNOPSIS
Removes a certificate from a store for the user or machine account.
.DESCRIPTION
The `Uninstall-Certificate` function uses .NET's certificates API to remove a certificate from a given store for the machine or current user. Use the thumbprint to identify which certificate to remove. The thumbprint is unique to each certificate. The user performing the removal must have read and write permission on the store where the certificate is located.
If the certificate isn't in the store, nothing happens, not even an error.
To uninstall a certificate from a remote computer, use the `Session`parameter, which was added in Carbon 2.1.0. You can create a new session with the `New-PSSession` cmdlet.
.EXAMPLE
> Uninstall-Certificate -Thumbprint 570895470234023dsaaefdbcgbefa -StoreLocation CurrentUser -StoreName My
Removes the 570895470234023dsaaefdbcgbefa certificate from the current user's Personal certificate store.
.EXAMPLE
> $cert = Get-Certificate -FriendlyName 'Carbon Testing Certificate' -StoreLocation LocalMachine -StoreName Root
> Uninstall-Certificate -Certificate $cert -StoreLocation LocalMachine -StoreName Root
Removes the certificate with friendly name 'Carbon Testing Certificate' from the local machine's Trusted Root Certification Authorities store.
.EXAMPLE
Uninstall-Certificate -Thumbprint 570895470234023dsaaefdbcgbefa -StoreLocation LocalMachine -StoreName 'SharePoint'
Demonstrates how to uninstall a certificate from a custom, non-standard store.
.EXAMPLE
> Uninstall-Certificate -Thumbprint 570895470234023dsaaefdbcgbefa -StoreLocation CurrentUser -StoreName My -Session (New-PSSession -ComputerName remote1,remote2)
Demonstrates how to uninstall a certificate from a remote computer.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true,ParameterSetName='ByThumbprintAndStoreName')]
[Parameter(Mandatory=$true,ParameterSetName='ByThumbprintAndCustomStoreName')]
[string]
# The thumbprint of the certificate to remove.
$Thumbprint,
[Parameter(Mandatory=$true,ParameterSetName='ByCertificateAndStoreName')]
[Parameter(Mandatory=$true,ParameterSetName='ByCertificateAndCustomStoreName')]
[Security.Cryptography.X509Certificates.X509Certificate2]
# The certificate to remove
$Certificate,
[Parameter(Mandatory=$true)]
[Security.Cryptography.X509Certificates.StoreLocation]
# The location of the certificate's store.
$StoreLocation,
[Parameter(Mandatory=$true,ParameterSetName='ByThumbprintAndStoreName')]
[Parameter(Mandatory=$true,ParameterSetName='ByCertificateAndStoreName')]
[Security.Cryptography.X509Certificates.StoreName]
# The name of the certificate's store.
$StoreName,
[Parameter(Mandatory=$true,ParameterSetName='ByThumbprintAndCustomStoreName')]
[Parameter(Mandatory=$true,ParameterSetName='ByCertificateAndCustomStoreName')]
[string]
# The name of the non-standard, custom store where the certificate should be un-installed.
$CustomStoreName,
[Management.Automation.Runspaces.PSSession[]]
# Use the `Session` parameter to uninstall a certificate on remote computer(s) using PowerShell remoting. Use `New-PSSession` to create a session.
#
# This parameter was added in Carbon 2.1.0.
$Session
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSCmdlet.ParameterSetName -like 'ByCertificate*' )
{
$Thumbprint = $Certificate.Thumbprint
}
$invokeCommandParameters = @{}
if( $Session )
{
$invokeCommandParameters['Session'] = $Session
}
Invoke-Command @invokeCommandParameters -ScriptBlock {
[CmdletBinding()]
param(
[string]
# The thumbprint of the certificate to remove.
$Thumbprint,
[Security.Cryptography.X509Certificates.StoreLocation]
# The location of the certificate's store.
$StoreLocation,
# The name of the certificate's store.
$StoreName,
[string]
# The name of the non-standard, custom store where the certificate should be un-installed.
$CustomStoreName
)
Set-StrictMode -Version 'Latest'
if( $CustomStoreName )
{
$storeNamePath = $CustomStoreName
}
else
{
$storeNamePath = $StoreName
if( $StoreName -eq [Security.Cryptography.X509Certificates.StoreName]::CertificateAuthority )
{
$storeNamePath = 'CA'
}
}
$certPath = Join-Path -Path 'Cert:\' -ChildPath $StoreLocation
$certPath = Join-Path -Path $certPath -ChildPath $storeNamePath
$certPath = Join-Path -Path $certPath -ChildPath $Thumbprint
if( -not (Test-Path -Path $certPath -PathType Leaf) )
{
Write-Debug -Message ('Certificate {0} not found.' -f $certPath)
return
}
$cert = Get-Item -Path $certPath
if( $CustomStoreName )
{
$store = New-Object 'Security.Cryptography.X509Certificates.X509Store' $CustomStoreName,$StoreLocation
}
else
{
$store = New-Object 'Security.Cryptography.X509Certificates.X509Store' ([Security.Cryptography.X509Certificates.StoreName]$StoreName),$StoreLocation
}
$store.Open( ([Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) )
try
{
$target = $cert.FriendlyName
if( -not $target )
{
$target = $cert.Subject
}
if( $PSCmdlet.ShouldProcess( ("certificate {0} ({1})" -f $certPath,$target), "remove" ) )
{
$store.Remove( $cert )
}
}
finally
{
$store.Close()
}
} -ArgumentList $Thumbprint,$StoreLocation,$StoreName,$CustomStoreName
}
Set-Alias -Name 'Remove-Certificate' -Value 'Uninstall-Certificate'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Uninstall-Directory
{
<#
.SYNOPSIS
Removes a directory, if it exists.
.DESCRIPTION
The `Uninstall-Directory` function removes a directory. If the directory doesn't exist, it does nothing. If the directory has any files or sub-directories, you will be prompted to confirm the deletion of the directory and all its contents. To avoid the prompt, use the `-Recurse` switch.
`Uninstall-Directory` was added in Carbon 2.1.0.
.EXAMPLE
Uninstall-Directory -Path 'C:\Projects\Carbon'
Demonstrates how to remove/delete a directory. In this case, the directory `C:\Projects\Carbon` will be deleted, if it exists.
.EXAMPLE
Uninstall-Directory -Path 'C:\Projects\Carbon' -Recurse
Demonstrates how to remove/delete a directory that has items in it. In this case, the directory `C:\Projects\Carbon` *and all of its files and sub-directories* will be deleted, if the directory exists.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]
# The path to the directory to create.
$Path,
[Switch]
# Delete the directory *and* everything under it.
$Recurse
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( (Test-Path -Path $Path -PathType Container) )
{
Remove-Item -Path $Path -Recurse:$Recurse
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Uninstall-Group
{
<#
.SYNOPSIS
Removes a *local* group.
.DESCRIPTION
The `Uninstall-Group` function removes a *local* group using .NET's [DirectoryServices.AccountManagement API](https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement.aspx). If the group doesn't exist, returns without doing any work or writing any errors.
This function was added in Carbon 2.1.0.
.LINK
Add-GroupMember
.LINK
Install-Group
.LINK
Remove-GroupMember
.LINK
Test-Group
.LINK
Test-GroupMember
.INPUTS
System.String
.EXAMPLE
Uninstall-WhsGroup -Name 'TestGroup1'
Demonstrates how to uninstall a group. In this case, the `TestGroup1` group is removed.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param
(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]
# The name of the group to remove/uninstall.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( -not (Test-Group -Name $Name) )
{
return
}
$group = Get-Group -Name $Name
if( -not $group )
{
return
}
if( $PSCmdlet.ShouldProcess(('local group {0}' -f $Name), 'remove') )
{
Write-Verbose -Message ('[{0}] -' -f $Name)
$group.Delete()
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Uninstall-IisAppPool
{
<#
.SYNOPSIS
Removes an IIS application pool.
.DESCRIPTION
If the app pool doesn't exist, nothing happens.
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Uninstall-IisAppPool -Name Batcave
Removes/uninstalls the `Batcave` app pool.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The name of the app pool to remove.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$appPool = Get-IisAppPool -Name $Name
if( $appPool )
{
if( $pscmdlet.ShouldProcess( ('IIS app pool {0}' -f $Name), 'remove' ) )
{
$appPool.Delete()
$appPool.CommitChanges()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Uninstall-IisWebsite
{
<#
.SYNOPSIS
Removes a website
.DESCRIPTION
Pretty simple: removes the website named `Name`. If no website with that name exists, nothing happens.
Beginning with Carbon 2.0.1, this function is not available if IIS isn't installed.
.LINK
Get-IisWebsite
.LINK
Install-IisWebsite
.EXAMPLE
Uninstall-IisWebsite -Name 'MyWebsite'
Removes MyWebsite.
.EXAMPLE
Uninstall-IisWebsite 1
Removes the website whose ID is 1.
#>
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=$true)]
[string]
# The name or ID of the website to remove.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( Test-IisWebsite -Name $Name )
{
$manager = New-Object 'Microsoft.Web.Administration.ServerManager'
try
{
$site = $manager.Sites | Where-Object { $_.Name -eq $Name }
$manager.Sites.Remove( $site )
$manager.CommitChanges()
}
finally
{
$manager.Dispose()
}
}
}
Set-Alias -Name 'Remove-IisWebsite' -Value 'Uninstall-IisWebsite'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Uninstall-Junction
{
<#
.SYNOPSIS
Uninstall a junction.
.DESCRIPTION
The `Uninstall-Junction` removes a junction that may or may not exist. If the junction exists, it is removed. If a junction doesn't exist, nothing happens.
If the path to uninstall is not a direcory, you *will* see errors.
`Uninstall-Junction` is new in Carbon 2.0.
Beginning in Carbon 2.2.0, you can uninstall junctions whose paths contain wildcard characters with the `LiteralPath` parameter.
.LINK
Install-Junction
.LINK
New-Junction
.LINK
Remove-Junction
.EXAMPLE
Uninstall-Junction -Path 'C:\I\Am\A\Junction'
Uninstall the `C:\I\Am\A\Junction`
.LINK
Test-PathIsJunction
Remove-Junction
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='Path')]
param(
[Parameter(Mandatory=$true,Position=0,ParameterSetName='Path')]
[string]
# The path to the junction to remove. Wildcards supported.
$Path,
[Parameter(Mandatory=$true,ParameterSetName='LiteralPath')]
[string]
# The literal path to the junction to remove. Use this parameter if the junction's path contains wildcard characters.
#
# This parameter was added in Carbon 2.2.0.
$LiteralPath
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $PSCmdlet.ParameterSetName -eq 'Path' )
{
if( [Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Path) )
{
Remove-Junction -Path $Path
return
}
$LiteralPath = $Path
}
if( (Test-Path -LiteralPath $LiteralPath) )
{
Remove-Junction -LiteralPath $LiteralPath
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Uninstall-PerformanceCounterCategory
{
<#
.SYNOPSIS
Removes an entire performance counter category.
.DESCRIPTION
Removes, with extreme prejudice, the performance counter category `CategoryName`. All its performance counters are also deleted. If the performance counter category doesn't exist, nothing happens. I hope you have good backups!
.EXAMPLE
Uninstall-PerformanceCounterCategory -CategoryName 'ToyotaCamry'
Removes the `ToyotaCamry` performance counter category and all its performance counters. So sad!
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The performance counter's category name that should be deleted.
$CategoryName
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( (Test-PerformanceCounterCategory -CategoryName $CategoryName) )
{
if( $pscmdlet.ShouldProcess( $CategoryName, 'uninstall performance counter category' ) )
{
[Diagnostics.PerformanceCounterCategory]::Delete( $CategoryName )
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Uninstall-ScheduledTask
{
<#
.SYNOPSIS
Uninstalls a scheduled task on the current computer.
.DESCRIPTION
The `Uninstall-ScheduledTask` function uses `schtasks.exe` to uninstall a scheduled task on the current computer. If the task doesn't exist, nothing happens.
.LINK
Get-ScheduledTask
.LINK
Test-ScheduledTask
.LINK
Install-ScheduledTask
.EXAMPLE
Uninstall-ScheduledTask -Name 'doc'
Demonstrates how to delete a scheduled task named `doc`.
.EXAMPLE
Uninstall-ScheduledTask -Name 'doc' -Force
Demonstrates how to delete a scheduled task that is currently running.
#>
[CmdletBinding(DefaultParameterSetName='AsBuiltinPrincipal')]
param(
[Parameter(Mandatory=$true)]
[Alias('TaskName')]
[string]
# The name of the scheduled task to uninstall.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$Name = Join-Path -Path '\' -ChildPath $Name
$MAX_TRIES = 5
$tryNum = 0
do
{
if( -not (Test-ScheduledTask -Name $Name) )
{
Write-Verbose ('Scheduled task ''{0}'' not found.' -f $Name)
return
}
$lastTry = (++$tryNum -ge $MAX_TRIES)
Write-Verbose ('Deleting scheduled task ''{0}''.' -f $Name)
$errFile = Join-Path -Path $env:TEMP -ChildPath ('Carbon+Uninstall-ScheduledTask+{0}' -f ([IO.Path]::GetRandomFileName()))
schtasks.exe /delete /tn $Name '/F' 2> $errFile | ForEach-Object {
if( $_ -match '\bERROR\b' )
{
if( $lastTry -or $err -notmatch 'The function attempted to use a name that is reserved for use by another transaction' )
{
Write-Error $_
}
}
elseif( $_ -match '\bWARNING\b' )
{
Write-Warning $_
}
else
{
Write-Verbose $_
}
}
if( $LASTEXITCODE )
{
$err = (Get-Content -Path $errFile) -join ([Environment]::NewLine)
if( -not $lastTry -and $err -match 'The function attempted to use a name that is reserved for use by another transaction' )
{
if( $Global:Error.Count -gt 0 )
{
$Global:Error.RemoveAt(0)
}
if( $Global:Error.Count -gt 0 )
{
$Global:Error.RemoveAt(0)
}
Write-Verbose ('Failed to delete scheduled task ''{0}'' (found ''The function attempted to use a name that is reserved for use by another transaction.'' error). Retrying (attempt #{1}).' -f $Name,$tryNum)
Start-Sleep -Milliseconds 100
continue
}
Write-Error $err
break
}
}
while( $true -and -not $lastTry)
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Uninstall-Service
{
<#
.SYNOPSIS
Removes/deletes a service.
.DESCRIPTION
Removes an existing Windows service. If the service doesn't exist, nothing happens. The service is stopped before being deleted, so that the computer doesn't need to be restarted for the removal to complete. Even then, sometimes it won't go away until a reboot. I don't get it either.
.LINK
Carbon_Service
.LINK
Install-Service
.EXAMPLE
Uninstall-Service -Name DeathStar
Removes the Death Star Windows service. It is destro..., er, stopped first, then destro..., er, deleted. If only the rebels weren't using Linux!
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string]
# The service name to delete.
$Name
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$service = Get-Service | Where-Object { $_.Name -eq $Name }
$sc = (Join-Path $env:WinDir system32\sc.exe -Resolve)
if( $service )
{
if( $pscmdlet.ShouldProcess( "service '$Name'", "remove" ) )
{
Stop-Service $Name
$output = & $sc delete $Name
if( $LASTEXITCODE )
{
if( $LASTEXITCODE -eq 1072 )
{
Write-Warning -Message ('The {0} service is marked for deletion and will be removed during the next reboot.{1}{2}' -f $Name,([Environment]::NewLine),($output -join ([Environment]::NewLine)))
}
else
{
Write-Error -Message ('Failed to uninstall {0} service (returned non-zero exit code {1}):{2}{3}' -f $Name,$LASTEXITCODE,([Environment]::NewLine),($output -join ([Environment]::NewLine)))
}
}
else
{
$output | Write-Verbose
}
}
}
}
Set-Alias -Name 'Remove-Service' -Value 'Uninstall-Service'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Uninstall-User
{
<#
.SYNOPSIS
Removes a user from the local computer.
.DESCRIPTION
Removes a *local* user account. If the account doesn't exist, nothing happens.
.LINK
Get-User
.LINK
Install-User
.LINK
Test-User
.LINK
Uninstall-User
.EXAMPLE
Uninstall-User -Username WTarkin
Removes the `WTarkin` *local* user account.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[ValidateLength(1,20)]
[string]
# The username of the account to remove.
$Username
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( Test-User -Username $username )
{
$user = Get-User -Username $Username
try
{
if( $pscmdlet.ShouldProcess( $Username, "remove local user" ) )
{
$user.Delete()
}
}
finally
{
$user.Dispose()
}
}
}
Set-Alias -Name 'Remove-User' -Value 'Uninstall-User'
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This function should only be available if the Windows PowerShell v3.0 Server Manager cmdlets aren't already installed.
if( -not (Get-Command -Name 'Get-WindowsFeature*' | Where-Object { $_.ModuleName -ne 'Carbon' }) )
{
function Uninstall-WindowsFeature
{
<#
.SYNOPSIS
Uninstalls optional Windows components/features.
.DESCRIPTION
The names of the features are different on different versions of Windows. For a list, run `Get-WindowsService`.
Feature names are case-sensitive. If a feature is already uninstalled, nothing happens.
**This function is not available on Windows 8/2012.**
.LINK
Get-WindowsFeature
.LINK
Install-WindowsService
.LINK
Test-WindowsService
.EXAMPLE
Uninstall-WindowsFeature -Name TelnetClient,TFTP
Uninstalls Telnet and TFTP.
.EXAMPLE
Uninstall-WindowsFeature -Iis
Uninstalls IIS.
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='ByName')]
param(
[Parameter(Mandatory=$true,ParameterSetName='ByName')]
[string[]]
# The names of the components to uninstall/disable. Feature names are case-sensitive. To get a list, run `Get-WindowsFeature`.
[Alias('Features')]
$Name,
[Parameter(ParameterSetName='ByFlag')]
[Switch]
# Uninstalls IIS.
$Iis,
[Parameter(ParameterSetName='ByFlag')]
[Switch]
# Uninstalls IIS's HTTP redirection feature.
$IisHttpRedirection,
[Parameter(ParameterSetName='ByFlag')]
[Switch]
# Uninstalls MSMQ.
$Msmq,
[Parameter(ParameterSetName='ByFlag')]
[Switch]
# Uninstalls MSMQ HTTP support.
$MsmqHttpSupport,
[Parameter(ParameterSetName='ByFlag')]
[Switch]
# Uninstalls MSMQ Active Directory Integration.
$MsmqActiveDirectoryIntegration
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
Write-Warning -Message ('Uninstall-WindowsFeature is obsolete and will be removed in a future major version of Carbon.')
if( -not (Assert-WindowsFeatureFunctionsSupported) )
{
return
}
if( $pscmdlet.ParameterSetName -eq 'ByFlag' )
{
$Name = Resolve-WindowsFeatureName -Name $PSBoundParameters.Keys
}
$featuresToUninstall = $Name |
ForEach-Object {
if( (Test-WindowsFeature -Name $_) )
{
$_
}
else
{
Write-Error ('Windows feature ''{0}'' not found.' -f $_)
}
} |
Where-Object { Test-WindowsFeature -Name $_ -Installed }
if( -not $featuresToUninstall -or $featuresToUninstall.Length -eq 0 )
{
return
}
if( $pscmdlet.ShouldProcess( "Windows feature(s) '$featuresToUninstall'", "uninstall" ) )
{
if( $useServerManager )
{
& servermanagercmd.exe -remove $featuresToUninstall
}
else
{
$featuresArg = $featuresToUninstall -join ';'
& ocsetup.exe $featuresArg /uninstall
$ocsetup = Get-Process 'ocsetup' -ErrorAction SilentlyContinue
if( -not $ocsetup )
{
Write-Error "Unable to find process 'ocsetup'. It looks like the Windows Optional Component setup program didn't start."
return
}
$ocsetup.WaitForExit()
}
}
}
Set-Alias -Name 'Uninstall-WindowsFeatures' -Value 'Uninstall-WindowsFeature'
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Unlock-IisConfigurationSection
{
<#
.SYNOPSIS
Unlocks a section in the IIS server configuration.
.DESCRIPTION
Some sections/areas are locked by IIS, so that websites can't enable those settings, or have their own custom configurations. This function will unlocks those locked sections. You have to know the path to the section. You can see a list of locked sections by running:
C:\Windows\System32\inetsrv\appcmd.exe unlock config /section:?
Beginning with Carbon 2.0.1, this function is available only if IIS is installed.
.EXAMPLE
Unlock-IisConfigSection -Name 'system.webServer/cgi'
Unlocks the CGI section so that websites can configure their own CGI settings.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[string[]]
# The path to the section to unlock. For a list of sections, run
#
# C:\Windows\System32\inetsrv\appcmd.exe unlock config /section:?
$SectionPath
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$SectionPath |
ForEach-Object {
$section = Get-IisConfigurationSection -SectionPath $_
$section.OverrideMode = 'Allow'
if( $pscmdlet.ShouldProcess( $_, 'unlocking IIS configuration section' ) )
{
$section.CommitChanges()
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
filter Unprotect-String
{
<#
.SYNOPSIS
Decrypts a string.
.DESCRIPTION
`Unprotect-String` decrypts a string encrypted via the Data Protection API (DPAPI) or RSA. It uses the DP/RSA APIs to decrypted the secret into an array of bytes, which is then converted to a UTF8 string. Beginning with Carbon 2.0, after conversion, the decrypted array of bytes is cleared in memory.
Also beginning in Carbon 2.0, use the `AsSecureString` switch to cause `Unprotect-String` to return the decrypted string as a `System.Security.SecureString`, thus preventing your secret from hanging out in memory. When converting to a secure string, the secret is decrypted to an array of bytes, and then converted to an array of characters. Each character is appended to the secure string, after which it is cleared in memory. When the conversion is complete, the decrypted byte array is also cleared out in memory.
`Unprotect-String` can decrypt using the following techniques.
## DPAPI
This is the default. The string must have also been encrypted with the DPAPI. The string must have been encrypted at the current user's scope or the local machien scope.
## RSA
RSA is an assymetric encryption/decryption algorithm, which requires a public/private key pair. This method decrypts a secret that was encrypted with the public key using the private key.
You can specify the private key in three ways:
* with a `System.Security.Cryptography.X509Certificates.X509Certificate2` object, via the `Certificate` parameter
* with a certificate in one of the Windows certificate stores, passing its unique thumbprint via the `Thumbprint` parameter, or via the `PrivateKeyPath` parameter, which can be a certificat provider path, e.g. it starts with `cert:\`.
* with an X509 certificate file, via the `PrivateKeyPath` parameter
.LINK
New-RsaKeyPair
.LINK
Protect-String
.LINK
http://msdn.microsoft.com/en-us/library/system.security.cryptography.protecteddata.aspx
.EXAMPLE
PS> $password = Unprotect-String -ProtectedString $encryptedPassword
Decrypts a protected string which was encrypted at the current user or default scopes using the DPAPI. The secret must have been encrypted at the current user's scope or at the local computer's scope.
.EXAMPLE
Protect-String -String 'NotSoSecretSecret' -ForUser | Unprotect-String
Demonstrates how Unprotect-String takes input from the pipeline. Adds 'NotSoSecretSecret' to the pipeline.
.EXAMPLE
Unprotect-String -ProtectedString $ciphertext -Certificate $myCert
Demonstrates how to encrypt a secret using RSA with a `System.Security.Cryptography.X509Certificates.X509Certificate2` object. You're responsible for creating/loading it. The `New-RsaKeyPair` function will create a key pair for you, if you've got a Windows SDK installed.
.EXAMPLE
Unprotect-String -ProtectedString $ciphertext -Thumbprint '44A7C27F3353BC53F82318C14490D7E2500B6D9E'
Demonstrates how to decrypt a secret using RSA with a certificate in one of the Windows certificate stores. All local machine and user stores are searched. The current user must have permission/access to the certificate's private key.
.EXAMPLE
Unprotect -ProtectedString $ciphertext -PrivateKeyPath 'C:\Projects\Security\publickey.cer'
Demonstrates how to encrypt a secret using RSA with a certificate file. The file must be loadable by the `System.Security.Cryptography.X509Certificates.X509Certificate` class.
.EXAMPLE
Unprotect -ProtectedString $ciphertext -PrivateKeyPath 'cert:\LocalMachine\My\44A7C27F3353BC53F82318C14490D7E2500B6D9E'
Demonstrates how to encrypt a secret using RSA with a certificate in the store, giving its exact path.
#>
[CmdletBinding(DefaultParameterSetName='DPAPI')]
param(
[Parameter(Mandatory = $true, Position=0, ValueFromPipeline = $true)]
[string]
# The text to decrypt.
$ProtectedString,
[Parameter(Mandatory=$true,ParameterSetName='RSAByCertificate')]
[Security.Cryptography.X509Certificates.X509Certificate2]
# The private key to use for decrypting.
$Certificate,
[Parameter(Mandatory=$true,ParameterSetName='RSAByThumbprint')]
[string]
# The thumbprint of the certificate, found in one of the Windows certificate stores, to use when decrypting. All certificate stores are searched. The current user must have permission to the private key.
$Thumbprint,
[Parameter(Mandatory=$true,ParameterSetName='RSAByPath')]
[string]
# The path to the private key to use for encrypting. Must be to an `X509Certificate2` file or a certificate in a certificate store.
$PrivateKeyPath,
[Parameter(ParameterSetName='RSAByPath')]
# The password for the private key, if it has one. It really should. Can be a `[string]` or a `[securestring]`.
$Password,
[Parameter(ParameterSetName='RSAByCertificate')]
[Parameter(ParameterSetName='RSAByThumbprint')]
[Parameter(ParameterSetName='RSAByPath')]
[Switch]
# If true, uses Direct Encryption (PKCS#1 v1.5) padding. Otherwise (the default), uses OAEP (PKCS#1 v2) padding. See [Encrypt](http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.encrypt(v=vs.110).aspx) for information.
$UseDirectEncryptionPadding,
[Switch]
# Returns the unprotected string as a secure string. The original decrypted bytes are zeroed out to limit the memory exposure of the decrypted secret, i.e. the decrypted secret will never be in a `string` object.
$AsSecureString
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$encryptedBytes = [Convert]::FromBase64String($ProtectedString)
if( $PSCmdlet.ParameterSetName -eq 'DPAPI' )
{
$decryptedBytes = [Security.Cryptography.ProtectedData]::Unprotect( $encryptedBytes, $null, 0 )
}
elseif( $PSCmdlet.ParameterSetName -like 'RSA*' )
{
if( $PSCmdlet.ParameterSetName -like '*ByPath' )
{
$passwordParam = @{ }
if( $Password )
{
$passwordParam = @{ Password = $Password }
}
$Certificate = Get-Certificate -Path $PrivateKeyPath @passwordParam
if( -not $Certificate )
{
return
}
}
elseif( $PSCmdlet.ParameterSetName -like '*ByThumbprint' )
{
$certificates = Get-ChildItem -Path ('cert:\*\*\{0}' -f $Thumbprint) -Recurse
if( -not $certificates )
{
Write-Error ('Certificate ''{0}'' not found.' -f $Thumbprint)
return
}
$Certificate = $certificates | Where-Object { $_.HasPrivateKey } | Select-Object -First 1
if( -not $Certificate )
{
Write-Error ('Certificate ''{0}'' ({1}) doesn''t have a private key.' -f $certificates[0].Subject, $Thumbprint)
return
}
}
if( -not $Certificate.HasPrivateKey )
{
Write-Error ('Certificate ''{0}'' ({1}) doesn''t have a private key. When decrypting with RSA, secrets are encrypted with the public key, and decrypted with a private key.' -f $Certificate.Subject,$Certificate.Thumbprint)
return
}
if( -not $Certificate.PrivateKey )
{
Write-Error ('Certificate ''{0}'' ({1}) has a private key, but it is currently null or not set. This usually means your certificate was imported or generated incorrectly. Make sure you''ve generated an RSA public/private key pair and are using the private key. If the private key is in the Windows certificate stores, make sure it was imported correctly (`Get-ChildItem $pathToCert | Select-Object -Expand PrivateKey` isn''t null).' -f $Certificate.Subject,$Certificate.Thumbprint)
return
}
[Security.Cryptography.RSACryptoServiceProvider]$privateKey = $null
if( $Certificate.PrivateKey -isnot [Security.Cryptography.RSACryptoServiceProvider] )
{
Write-Error ('Certificate ''{0}'' (''{1}'') is not an RSA key. Found a private key of type ''{2}'', but expected type ''{3}''.' -f $Certificate.Subject,$Certificate.Thumbprint,$Certificate.PrivateKey.GetType().FullName,[Security.Cryptography.RSACryptoServiceProvider].FullName)
return
}
try
{
$privateKey = $Certificate.PrivateKey
$decryptedBytes = $privateKey.Decrypt( $encryptedBytes, (-not $UseDirectEncryptionPadding) )
}
catch
{
if( $_.Exception.Message -match 'Error occurred while decoding OAEP padding' )
{
[int]$maxLengthGuess = ($privateKey.KeySize - (2 * 160 - 2)) / 8
Write-Error (@'
Failed to decrypt string using certificate '{0}' ({1}). This can happen when:
* The string to decrypt is too long because the original string you encrypted was at or near the maximum allowed by your key's size, which is {2} bits. We estimate the maximum string size you can encrypt is {3} bytes. You may get this error even if the original encrypted string is within a couple bytes of that maximum.
* The string was encrypted with a different key
* The string isn't encrypted
{4}: {5}
'@ -f $Certificate.Subject, $Certificate.Thumbprint,$privateKey.KeySize,$maxLengthGuess,$_.Exception.GetType().FullName,$_.Exception.Message)
return
}
elseif( $_.Exception.Message -match '(Bad Data|The parameter is incorrect)\.' )
{
Write-Error (@'
Failed to decrypt string using certificate '{0}' ({1}). This usually happens when the padding algorithm used when encrypting/decrypting is different. Check the `-UseDirectEncryptionPadding` switch is the same for both calls to `Protect-String` and `Unprotect-String`.
{2}: {3}
'@ -f $Certificate.Subject,$Certificate.Thumbprint,$_.Exception.GetType().FullName,$_.Exception.Message)
return
}
Write-Error -Exception $_.Exception
return
}
}
try
{
if( $AsSecureString )
{
$secureString = New-Object 'Security.SecureString'
[char[]]$chars = [Text.Encoding]::UTF8.GetChars( $decryptedBytes )
for( $idx = 0; $idx -lt $chars.Count ; $idx++ )
{
$secureString.AppendChar( $chars[$idx] )
$chars[$idx] = 0
}
$secureString.MakeReadOnly()
return $secureString
}
else
{
[Text.Encoding]::UTF8.GetString( $decryptedBytes )
}
}
finally
{
[Array]::Clear( $decryptedBytes, 0, $decryptedBytes.Length )
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Use-CallerPreference
{
<#
.SYNOPSIS
Sets the PowerShell preference variables in a module's function based on the callers preferences.
.DESCRIPTION
Script module functions do not automatically inherit their caller's variables, including preferences set by common parameters. This means if you call a script with switches like `-Verbose` or `-WhatIf`, those that parameter don't get passed into any function that belongs to a module.
When used in a module function, `Use-CallerPreference` will grab the value of these common parameters used by the function's caller:
* ErrorAction
* Debug
* Confirm
* InformationAction
* Verbose
* WarningAction
* WhatIf
This function should be used in a module's function to grab the caller's preference variables so the caller doesn't have to explicitly pass common parameters to the module function.
This function is adapted from the [`Get-CallerPreference` function written by David Wyatt](https://gallery.technet.microsoft.com/scriptcenter/Inherit-Preference-82343b9d).
There is currently a [bug in PowerShell](https://connect.microsoft.com/PowerShell/Feedback/Details/763621) that causes an error when `ErrorAction` is implicitly set to `Ignore`. If you use this function, you'll need to add explicit `-ErrorAction $ErrorActionPreference` to every function/cmdlet call in your function. Please vote up this issue so it can get fixed.
.LINK
about_Preference_Variables
.LINK
about_CommonParameters
.LINK
https://gallery.technet.microsoft.com/scriptcenter/Inherit-Preference-82343b9d
.LINK
http://powershell.org/wp/2014/01/13/getting-your-script-module-functions-to-inherit-preference-variables-from-the-caller/
.EXAMPLE
Use-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
Demonstrates how to set the caller's common parameter preference variables in a module function.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
#[Management.Automation.PSScriptCmdlet]
# The module function's `$PSCmdlet` object. Requires the function be decorated with the `[CmdletBinding()]` attribute.
$Cmdlet,
[Parameter(Mandatory = $true)]
[Management.Automation.SessionState]
# The module function's `$ExecutionContext.SessionState` object. Requires the function be decorated with the `[CmdletBinding()]` attribute.
#
# Used to set variables in its callers' scope, even if that caller is in a different script module.
$SessionState
)
Set-StrictMode -Version 'Latest'
# List of preference variables taken from the about_Preference_Variables and their common parameter name (taken from about_CommonParameters).
$commonPreferences = @{
'ErrorActionPreference' = 'ErrorAction';
'DebugPreference' = 'Debug';
'ConfirmPreference' = 'Confirm';
'InformationPreference' = 'InformationAction';
'VerbosePreference' = 'Verbose';
'WarningPreference' = 'WarningAction';
'WhatIfPreference' = 'WhatIf';
}
foreach( $prefName in $commonPreferences.Keys )
{
$parameterName = $commonPreferences[$prefName]
# Don't do anything if the parameter was passed in.
if( $Cmdlet.MyInvocation.BoundParameters.ContainsKey($parameterName) )
{
continue
}
$variable = $Cmdlet.SessionState.PSVariable.Get($prefName)
# Don't do anything if caller didn't use a common parameter.
if( -not $variable )
{
continue
}
if( $SessionState -eq $ExecutionContext.SessionState )
{
Set-Variable -Scope 1 -Name $variable.Name -Value $variable.Value -Force -Confirm:$false -WhatIf:$false
}
else
{
$SessionState.PSVariable.Set($variable.Name, $variable.Value)
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Write-DscError
{
<#
.SYNOPSIS
Writes DSC errors out as errors.
.DESCRIPTION
The Local Configuration Manager (LCM) applies configuration in a separate process space as a background service which writes its errors to the `Microsoft-Windows-DSC/Operational` event log. This function is intended to be used with `Get-DscError`, and will write errors returned by that function as PowerShell errors.
`Write-DscError` is new in Carbon 2.0.
.OUTPUTS
System.Diagnostics.Eventing.Reader.EventLogRecord
.LINK
Get-DscError
.EXAMPLE
Get-DscError | Write-DscError
Demonstrates how `Write-DscError` is intended to be used. `Get-DscError` gets the appropriate event objects that `Write-DscError` writes out.
#>
[CmdletBinding()]
[OutputType([Diagnostics.Eventing.Reader.EventLogRecord])]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[Diagnostics.Eventing.Reader.EventLogRecord[]]
# The error record to write out as an error.
$EventLogRecord,
[Switch]
# Return the event log record after writing an error.
$PassThru
)
process
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
foreach( $record in $EventLogRecord )
{
[string[]]$property = $record.Properties | Select-Object -ExpandProperty Value
$message = $property[-1]
Write-Error -Message ('[{0}] [{1}] [{2}] {3}' -f $record.TimeCreated,$record.MachineName,($property[0..($property.Count - 2)] -join '] ['),$message)
if( $PassThru )
{
return $record
}
}
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Write-File
{
<#
.SYNOPSIS
Writes text to a file, retrying if the write fails.
.DESCRIPTION
The `Write-File` function writes text file to a file, and will retry if the write fails. Use this function if you need to write text files that can be intermittently locked, like the Windows hosts file.
By default, it will retry 30 times, waiting 100 milliseconds between each try. You can control the number of retries and the wait between retries with the `MaximumTries` and `RetryDelayMilliseconds` parameters, respectively.
All errors raised while trying to write the file are ignored, except the error raised on the last try.
This function was introduced in Carbon 2.2.0.
.EXAMPLE
$lines | Write-File -Path 'C:\Path\to\my\file'
Demonstrates how to write lines to a text file using the pipeline.
.EXAMPLE
Write-File -Path 'C:\Path\to\my\file' -InputObject $lines
Demonstrates how to write lines to a text file using a variable.
.EXAMPLE
$lines | Write-File -Path 'C:\Path\to\my\file' -MaximumRetries 10 -RetryDelayMilliseconds 1000
Demonstrates how to control how long to retry writing the text file. In this case, `Write-File` will try 10 times, waiting one second between tries.
.EXAMPLE
$lines | Write-File -Path 'C:\Path\to\my\file' -ErrorVariable 'writeErrors'
Demonstrates how to check if the write failed. In this case, errors are copied to a 'writeErrors' variable, so you would check if this error variable has any items.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
# The path to the file to read.
$Path,
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[AllowEmptyCollection()]
[AllowEmptyString()]
[string[]]
# The contents of the file
$InputObject,
[int]
# The number of tries before giving up reading the file. The default is 100.
$MaximumTries = 30,
[int]
# The number of milliseconds to wait between tries. Default is 100 milliseconds.
$RetryDelayMilliseconds = 100
)
begin
{
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
$Path = Resolve-Path -Path $Path
if( -not $Path )
{
return
}
$content = New-Object -TypeName 'Collections.Generic.List[object]'
}
process
{
if( -not $Path )
{
return
}
$InputObject | ForEach-Object { $content.Add( $_ ) } | Out-Null
}
end
{
if( -not $Path )
{
return
}
$cmdErrors = @()
$tryNum = 1
$errorAction = @{ 'ErrorAction' = 'SilentlyContinue' }
do
{
$exception = $false
$lastTry = $tryNum -eq $MaximumTries
if( $lastTry )
{
$errorAction = @{}
}
$numErrorsAtStart = $Global:Error.Count
try
{
Set-Content -Path $Path -Value $content @errorAction
}
catch
{
if( $lastTry )
{
Write-Error -ErrorRecord $_
}
}
$numErrors = $Global:Error.Count - $numErrorsAtStart
if( $numErrors -and -not $lastTry )
{
for( $idx = 0; $idx -lt $numErrors; ++$idx )
{
$Global:Error[0] | Out-String | Write-Debug
$Global:Error.RemoveAt(0)
}
}
if( $numErrors )
{
if( -not $lastTry )
{
Write-Debug -Message ('Failed to write file ''{0}'' (attempt #{1}). Retrying in {2} milliseconds.' -f $Path,$tryNum,$RetryDelayMilliseconds)
Start-Sleep -Milliseconds $RetryDelayMilliseconds
}
}
else
{
break
}
}
while( $tryNum++ -le $MaximumTries )
}
}
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
function Write-IisVerbose
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=0)]
[string]
# The name of the site.
$SiteName,
[string]
$VirtualPath = '',
[Parameter(Position=1)]
[string]
# The name of the setting.
$Name,
[Parameter(Position=2)]
[string]
$OldValue = '',
[Parameter(Position=3)]
[string]
$NewValue = ''
)
Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
if( $VirtualPath )
{
$SiteName = Join-IisVirtualPath -Path $SiteName -ChildPath $VirtualPath
}
Write-Verbose -Message ('[IIS Website] [{0}] {1,-34} {2} -> {3}' -f $SiteName,$Name,$OldValue,$NewValue)
}
<#
.SYNOPSIS
Imports the Carbon module.
.DESCRIPTION
Intelligently imports the Carbon module, re-importing it if needed. Carbon will be re-imported if:
* a different version is currently loaded
* any of Carbon's files were modified since it was last imported with this script
* the `Force` switch is set
.EXAMPLE
Import-Carbon.ps1
Imports the Carbon module, re-loading it if its already loaded.
#>
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter()]
[string]
# The prefix to use on all the module's functions, cmdlets, etc.
$Prefix,
[Switch]
# Reload the module no matter what.
$Force
)
#Requires -Version 4
Set-StrictMode -Version 'Latest'
$carbonPsd1Path = Join-Path -Path $PSScriptRoot -ChildPath 'Carbon.psd1' -Resolve
$startedAt = Get-Date
$loadedModule = Get-Module -Name 'Carbon'
if( $loadedModule )
{
if( -not $Force -and ($loadedModule | Get-Member 'ImportedAt') )
{
$importedAt = $loadedModule.ImportedAt
$newFiles = Get-ChildItem -Path $PSScriptRoot -File -Recurse |
Where-Object { $_.LastWriteTime -gt $importedAt }
if( $newFiles )
{
Write-Verbose -Message ('Reloading Carbon module. The following files were modified since {0}:{1} * {2}' -f $importedAt,([Environment]::NewLine),($newFiles -join ('{0} * ' -f ([Environment]::NewLine))))
$Force = $true
}
}
$thisModuleManifest = Test-ModuleManifest -Path $carbonPsd1Path
if( $thisModuleManifest )
{
if( -not $Force -and $thisModuleManifest.Version -ne $loadedModule.Version )
{
Write-Verbose -Message ('Reloading Carbon module. Module from {0} at version {1} not equal to module from {2} at version {3}.' -f $loadedModule.ModuleBase,$loadedModule.Version,(Split-Path -Parent -Path $thisModuleManifest.Path),$thisModuleManifest.Version)
$Force = $true
}
}
}
else
{
$Force = $true
}
if( -not $Force )
{
return
}
$importModuleParams = @{ }
if( $Prefix )
{
$importModuleParams.Prefix = $Prefix
}
if( $Force -and $loadedModule )
{
# Remove so we don't get errors about conflicting type data.
Remove-Module -Name 'Carbon' -Verbose:$false -WhatIf:$false
}
Write-Verbose -Message ('Importing Carbon ({0}).' -f $carbonPsd1Path)
Import-Module $carbonPsd1Path -ErrorAction Stop -Verbose:$false @importModuleParams
if( -not (Get-Module -Name 'Carbon' | Get-Member -Name 'ImportedAt') )
{
Get-Module -Name 'Carbon' | Add-Member -MemberType NoteProperty -Name 'ImportedAt' -Value (Get-Date)
}
if( $Force )
{
$loadedModule = Get-Module -Name 'Carbon'
$loadedModule.ImportedAt = Get-Date
}
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2012 - 2015 Aaron Jensen
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Carbon
Copyright 2012 - 2015 Aaron Jensen
<#
.SYNOPSIS
Example build server setup script.
.DESCRIPTION
This sample script shows how to setup a simple build server running CruiseControl.NET as a Windows Service.
#>
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[CmdletBinding()]
param(
)
#Requires -Version 4
Set-StrictMode -Version Latest
& (Join-Path $PSScriptRoot ..\Import-Carbon.ps1 -Resolve)
$ccservicePath = 'Path\to\ccservice.exe'
$ccserviceUser = 'example.com\CCServiceUser'
$ccservicePassword = 'CCServiceUserPassword'
Install-Service -Name CCService -Path $ccservicePath -Username $ccserviceUser -Password $ccservicePassword
$pathToVersionControlRepository = 'Path\to\version\control\repository'
$pathToBuildOutput = 'Path\to\build\output'
Grant-Permission -Identity $ccserviceUser -Permission FullControl -Path $pathToVersionControlRepository
Grant-Permission -Identity $ccserviceUser -Permission FullControl -Path $pathToBuildOutput
<#
.SYNOPSIS
Example script showing how to setup a simple web server.
#>
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[CmdletBinding()]
param(
)
#Requires -Version 4
Set-StrictMode -Version Latest
& (Join-Path $PSSCriptRoot ..\Import-Carbon.ps1 -Resolve)
$deploymentWritersGroupName = 'DeploymentWriters'
$deploymnetReadersGroupName = 'DeploymentReaders'
$ccnetServiceUser = 'example.com\CCServiceUser'
Install-Group -Name $deploymentWritersGroupName `
-Description 'Users allowed to write to the deployment share.' `
-Members $ccnetServiceUser
Install-Group -Name $deploymnetReadersGroupName `
-Description 'Users allowed to read the deployment share.' `
-Members 'Everyone'
$websitePath = '\Path\to\website\directory'
Grant-Permission -Path $websitePath -Permission FullControl `
-Identity $deploymentWritersGroupName
Grant-Permission -Path $websitePath -Permission Read `
-Identity $deploymnetReadersGroupName
$deployShareName = 'Deploy'
Install-Share -Name $deployShareName `
-Path $websitePath `
-Description 'Share used by build server to deploy website changes.' `
-FullAccess $deploymentWritersGroupName `
-ReadAccess $deploymnetReadersGroupName
$sslCertPath = 'Path\to\SSL\certificate.cer'
$cert = Install-Certificate -Path $sslCertPath -StoreLocation LocalMachine -StoreName My
Set-SslCertificateBinding -ApplicationID ([Guid]::NewGuid()) -Thumbprint $cert.Thumbprint
$appPoolName = 'ExampleAppPool'
Install-IisAppPool -Name $appPoolName -ServiceAccount NetworkService
Install-IisWebsite -Path $websitePath -Name 'example1.get-carbon.org' `
-Bindings ('http/*:80','https/*:443') -AppPoolName $appPoolName
Set-DotNetConnectionString -Name 'example1DB' `
-Value 'Data Source=db.example1.get-carbon.org; Initial Catalog=example1DB; Integrated Security=SSPI;' `
-Framework64 `
-Clr4
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2012 - 2015 Aaron Jensen
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Carbon
Copyright 2012 - 2015 Aaron Jensen
# 2.2.0 (11 May 2016)
## Enhancements
* Aded a `LiteralPath` parameter to `Test-PathIsJunction` for testing paths that contain wildcard characters (e.g. `[`, `]`, etc.).
* `Remove-Junction` now supports removing multiple junctions with wildcards.
* Added a `LiteralPath` parameter to `Remove-Junction` for deleting junctions whose paths contain wildcard characters (e.g. `[`, `]`, etc.).
* Added a `LiteralPath` parameter to `Uninstall-Junction` for deleting junctions whose paths contain wildcard characters (e.g. `[`, `]`, etc.).
* Created `Remove-DotNetAppSetting` function for removing app settings from .NET framework machine.config files.
* Created `Read-File` function for reading text files and retrying if the read fails. Good for reading files that get intermittently locked, like the Windows hosts file.
* Created `Write-File` function for writing text files and retrying if the write fails. Good for writing files that get intermittently locked, like the Windows hosts file.
* Made the following functions obsolete:
* `Get-WindowsFeature`
* `Install-Msmq`
* `Install-WindowsFeature`
* `Resolve-WindowsFeatureName`
* `Uninstall-WindowsFeature`
## Bug Fixes
* Fixed: `Add-GroupMember`, over PowerShell remoting, fails to add a member to groups that have non-local users/groups (fixes [issue #187: Add-GroupMember fails when using PowerShell Remoting](https://bitbucket.org/splatteredbits/carbon/issues/187/add-groupmember-fails-when-using))
* Fixed: `Remove-GroupMember`, over PowerShell remoting, fails to remove a member from groups that have non-local users/groups.
* Fixed: `Test-PathIsJunction` returns multiple results if the `Path` parameter contains wildcards and matches multiple items.
* Fixed: `Install-Junction` can't install a junction whose path contains wildcard characters (fixes [issue #190](https://bitbucket.org/splatteredbits/carbon/issues/190/install-junction-fails-when-the-path)).
* Fixed: `New-Junction` writes wrong error when creating an existing junction whose path contains wildcard characters.
* Fixed: `Install-Service` doesn't update/change an existing service's account when using the `Credential` parameter (fixes [issue #185](https://bitbucket.org/splatteredbits/carbon/issues/185/install-service-never-updates-logon-as-if)).
* Fixed: `Uninstall-FileShare` fails if a share's physical path doesn't exist.
* Fixed (hopefully): `Get-FileSharePermission` writes an error if a share's security information is corrupted (fixes [issue #188](https://bitbucket.org/splatteredbits/carbon/issues/188/get-filesharepermission-crashes-when-a)). I was unable to reproduce the error, and the error was reported anonyously, so I did my best.
* Fixed: `Get-PowerShellModuleInstallPath` returns multiple paths if the standard PowerShell module path is listed twice in the `PSModulePath` environment variable.
* Fixed: Chocolatey package fails if the standard PowerShell module path is listed twice in the`PSModulePath` environment (fixes [issue #192](https://bitbucket.org/splatteredbits/carbon/issues/192/installation-of-carbon-via-chocolatey)).
* Fixed: `Get-PowerShellModuleInstallPath` doesn't return the module install path if it doesn't exist. Sometimes it doesn't yet.
* Fixed: `Carbon_ScheduledTask` and `Carbon_IniFile` DSC resources' `Get-TargetResource` functions don't return correct resource properties and causes `Get-DscConfiguration` to fail (fixes [issue #193](https://bitbucket.org/splatteredbits/carbon/issues/193/get-targetresource-returns-taskname-in-its)).
* Fixed: `Carbon_FirewallRule` DSC resource always re-installs a firewall rule if `Profile` property contains multiple values (i.e. it doesn't properly parse netsh output).
* Fixed: `about_Carbon_Installation` help topic had a typo.
* Fixed: `Set-HostsEntry` fails to stop when the hosts file is in use and can't be read.
# 2.1.1 (25 February 2016)
## Bug Fixes
* Fixed: unable to publish module to PowerShell Gallery because `RequiredAssemblies` module manifest data used an absolute path generated with `Join-Path` and `$PSScriptRoot`, which aren't allowed in module manifests.
* Fixed: missing PowerShell Gallery tags, license URI, project URI, and release notes metadata.
* Fixed: copyright date in module manifest is 2015.
* Fixed: PowerShell gallery missing function list.
* Fixed: Restricted user accounts can't import Carbon ([issue #180](https://bitbucket.org/splatteredbits/carbon/issues/180)).
* Fixed: `Carbon_Privilege` DSC resource fails to remove all a user's privileges ([issue #178](https://bitbucket.org/splatteredbits/carbon/issues/178)).
* Fixed: `Remove-IniEntry` fails to remove last INI entry in a file ([issue #179](https://bitbucket.org/splatteredbits/carbon/issues/179)).
# 2.1.0 (8 February 2016)
## New Functions
* `Get-HttpUrlAcl`: uses Windows API to return HTTP URL ACLs; replaces the `netsh http show urlacl` command.
* `Grant-HttpUrlPermission`: uses Windows API to grant listen/delegate permissions on HTTP URLs; replaces the `netsh http add urlacl` command.
* `Revoke-HttpUrlPermission`: uses Windows API to revoke all a user or group's permissions on HTTP URLs; replaces the `netsh http delete urlacl` command.
* `Install-Directory`: creates a directory (and any missing parents), if it doesn't exist already. Finally!
* `Uninstall-Directory`: removes a directory, if it exists. Finally!
* `Uninstall-Group`: uses the `DirectoryServices.AccountManagement` .NET API to remove a group, if it exists.
* `Test-GroupMember`: uses the `DirectoryServices.AccountManagemetn` .NET API to test if a principal is a member of a group.
## New DSC Resource
* `Carbon_Group`: resource for configuring local groups.
## Bug Fixes
* Fixed: `Install-FileShare` always re-configures existing shares; it doesn't properly detect permissions that need to be removed.
* Fixed: `Set-IniEntry` fails to preserve unicode characters with diacritics in INI entry names and values.
* Fixed: `Remove-IniEntry` fails to preserve unicode characters with diacritics in INI entry names and values.
* Fixed: `Set-HostsEntry` leaves trailing tabs and whitespace after all but the last line.
* Fixed: `Get-PowerShellModuleInstallPath` returns wrong path for PowerShell 4.
* Fixed: `Protect-String` fails when Carbon is installed in a module path that contains spaces ([fixes issue #174](https://bitbucket.org/splatteredbits/carbon/issues/174/protect-string-throws-when-module-path)).
* Fixed: `New-RsaKeyPair` generates a key pair that isn't supported for encrypting/decrypting DSC credentials or supported by the CMS message cmdlets.
* Fixed: `Get-ScheduledTask` returns invalid task commands when those commands contain quotes (works around an issue where `schtasks.exe` CSV output can't be parsed correctly by `ConvertFrom-Csv`).
* Fixed: `Add-GroupMember` and `Remove-GroupMember` fail when adding `Everyone` or `NT Service\*` accounts to a group ([fixes issue #177](https://bitbucket.org/splatteredbits/carbon/issues/177/add-groupmembers-201-doesnt-like-vsa-names)).
* Fixed: `Get-SheduledTask` writes an error if a scheduled task's XML definition is for an executable and doesn't contain an arguments element.
## Other Improvements
* Obsolete function parameters will no longer show in Intellisense (added the `DontShow` parameter property).
* `Test-AdminPrivilege`: changed its verbose message to a debug message.
* `Set-HostsEntry`:
* only updates hosts file if it needs to change
* added an improved verbose message when setting a hosts entry
* improved error handling when hosts file can't be opened for reading
* `Install-Certificate` can now install a certificate on a remote computer.
* `Initialize-Lcm` now uses `Install-Certificate` to install the decryption certificate on the remote computer.
* `Uninstall-Certificate` can now uninstall a certificate on a remote computer.
* The following functions now write warning if you pass them a plain-text password. You should pass a `SecureString` instead.
* `Install-Certificate`
* `Initialize-Lcm`
* `New-RsaKeyPair`:
* Refactored to use `certreq.exe` instead of `makecert.exe` and `pvk2pfx.exe`.
* Can now run non-interactively: added a `-Password` parameter used to protect the private key (it used to prompt you).
* Fixed: generates a key pair that isn't supported for encrypting/decrypting DSC credentials or supported by the CMS message cmdlets.
* Made the `-ValidFrom` and `-Authority` parameters obsolete.
* Added some verbose messages to `Install-Group` and `Add-MemberToGroup` when they create/modify their objects.
* `Install-Group` only saves changes to a group if changes were made.
# 2.0.1 (19 October 2015)
* Fixed: errors importing Carbon when IIS not installed on Windows 2012 R2 and Windows 10 (fixes [issue 168: Cannot import Carbon 2.0 module due to issues with IIS related functionality](https://bitbucket.org/splatteredbits/carbon/issues/168)).
* Fixed Carbon copyright statements.
* Improved Carbon's module description.
# 2.0.0 (10 October 2015)
## Overview
Carbon version 2.0 is a *huge* release, with lots of new enhancements and bug fixes. We hope you like them. Carbon 2.0 now requires PowerShell 4, so it is not backwards-compatabile with Carbon 1.x. Because of this, we made some additional backwards-incompatible changes. See the `Upgrade Instructions` section for things to look out for.
If you're upgrading from a previous 2.0 alpha release, you'll want to review the changes since your alpha version (found after the *Upgrade Instructions* section). We improved backwards-compatability with Carbon 1.x since the last alpha release, but that broke compatability with the alphas.
## Upgrade Instructions
Make sure you're running PowerShell 4.
`Install-Certificate`'s parameters have changed:
* Remove the `Exportable` switch from any usages of `Install-Certificate` when installing from an `X509Certificate2` *object*, since that switch only gets used when installing a certificate from a file.
Some functions now return different objects and/or the objects returned have changed:
* Use the `Sid` property on objects returned by `Test-Identity` when using the `PassThru` switch: it now returns a `Carbon.Identity` object if the identity exists *and* you use the `-PassThru` switch, e.g. `Test-Identity -Name $userName -PassThru | Select-Object -Expand 'Sid'`.
* Update usages of `Carbon.Computer.ProgramInstallInfo`'s `Version` property (returned by `Get-ProgramInstallInfo`). It was an `int` and is now a [Version](http://msdn.microsoft.com/en-us/library/y0hf9t2e.aspx) object.
The Carbon assembly was re-organized. If you were reaching into `Carbon.dll` (***NOT RECOMMENDED***), you'll want to:
* Rename usages of `[Carbon.AdvApi32]` class to `[Carbon.Service.ServiceSecurity]`.
* Rename usages of `[Carbon.Lsa]` class to `[Carbon.Security.Privilege]`.
* Rename usages of `[Carbon.Win32]` class to `[Carbon.FileSystem.Path]`.
* Rename usages of `[Carbon.HandleInfo]` class to `[Carbon.Win32.HandleInfo]`.
* Remove usages of `[Carbon.Lsa]::LookupPrivilegeValue` class method. It was incorrectly exposed as a public method.
* Remove usages of `[Carbon.Kernel32]::LocalFree` class method. It was incorrectly exposed as a public method.
The following commands no longer return the stdout output from the console applications each one calls. To see the old output, use the `-Verbose` switch. Remove any usage of the output you were processing.
* All IIS functions.
* `Disable-FirewallStatefulFtp`
* `Enable-FirewallStatefulFtp`
* `Install-Service`
* `Install-SmbShare`
* `Remove-SslCertificateBinding`
* `Set-SslCertificateBinding`
* `Uninstall-Service`
The following functions' internal behavior has changed. This may or may not impact you.
* `Grant-Permission` now only grants permissions on an object if those permissions aren't present. To preserve previous behavior, add the `-Force` switch to all `Grant-Permission` usages.
* `Grant-Permission` now writes an error if you don't have access to a private key. Previously, it would skip the key without any messages.
* `Install-Msi` (fka `Invoke-WindowsInstaller`) now only installs the MSI if it isn't already installed. To preserve the previous behavior and always install, add the `-Force` switch to all `Invoke-WindowsInstaller`\`Install-Msi` usages.
* All IIS functions were re-written to use the `Microsoft.Web.Administration` API instead of `appcmd.exe`.
* `Install-IisWebsite` no longer deletes and re-creates websites. If a website exists, it updates its configuration to match parameters passed in. To preserve previous behavior and delete the website before installing, use the `-Force` switch.
* `Install-IisVirtualDirectory` no longer deletes and re-creates virtual directories. If a virtual directory exists, its configuration is updated in place. To preserve previous behavior and delete the virtual directory before installing, use the `Force` switch.
* `Install-FileShare` (fka `Install-SmbShare`) no longer deletes and re-creates the share, instead it modifies existing shares in place. To preserve previous behavior and delete existing shares before re-creating, use the `Force` switch.
* `Set-RegistryKeyValue` only sets the value if the value doesn't exist or the current value is different than the desired value.
We've added parameter validation to some functions. This shouldn't impact anybody, since if you were passing data that breaks this new validation, the function wouldn't have worked even in previous versions of Carbon.
* Ensure that all thumbprints passed to `Set-SslCertificateBinding` are valid (40 character hex strings), since it now validates thumbprints.
* Check that all IP addresses passed to `Set-HostsEntry` are valid IP v4 or v6 addresses. `Set-HostsEntry`'s IPAddress parameter is now a `System.Net.IPAddress` object. Previously it was a string validated with a regular expression, so you *should* be OK.
All Carbon functions now respect each caller's common parameters (e.g. `-Verbose`, `-ErrorAction`, etc.). This means if you pass a common parameter to a script that calls a Carbon function, that Carbon function will use that common parameter. This may or may not impact you.
## Bug Fixes
* Carbon's `System.ServiceProcess.ServiceController` extended type data causes errors when PowerShell formats `System.ServiceProcess.ServiceController` objects that represent services on remote computers.
* `Compress-Item` doesn't remove handled errors from global error array.
* `Grant-Permission` fails with an unhelpful error message if it is unable to get the ACL on a private key.
* `Install-Msi` didn't properly detect when installation failed.
* `Install-ScheduledTask` fails under PowerShell 5 to create a scheduled task to run on Sunday.
* `Install-Service`:
* No longer writes a warning about being unable to stop an already stopped service (fixes [issue #158](https://bitbucket.org/splatteredbits/carbon/issues/158/install-service-extraneous-warning-about)).
* Starting the service now respects caller's error action preference. Before, `Start-Service` would write an error even if somone called `Install-Service` with an `Ignore` or `SilentlyContinue` error action preference.
* Service arguments that are quoted still get quoted. Now, quotes are trimmed before arguments are quoted.
* `Set-EnvironmentVariable` fails to set process-level environment variable.
* `Set-HostsEntry` fails to preserve whitespace if existing lines end with a comment/description. Thanks to [Konstantin Ushenin](https://vk.com/kostanew) for the fix.
## Enhancements
### General
* Carbon now requires PowerShell 4.
* `Import-Carbon.ps1` is more intelligent about when it tries to re-load Carbon. It will force a re-import of Carbon if any of Carbon's files have changed or the version has changed.
* Added new `FileIndex`, `LinkCount`, and `VolumeSerialNumber` extended type data on `System.IO.FileInfo` objects for getting a file's index, its hard link count, and volume serial number, respectively.
* The product version of the Carbon assembly now includes pre-release version information, as defined by the [Semantic Versioning specification](http://semver.org). To get this version, run `Get-Item Carbon.dll | Select-Object -ExpandProperty 'VersionInfo' | Select-Object -ExpandProperty 'ProductVersion'`.
* The Carbon NuGet package now supports installing and uninstalling under Chocolatey.
* All IIS functions were re-written to use the `Microsoft.Web.Administration` API instead of `appcmd.exe`. As a side effect, they no longer return `appcmd.exe` console output.
* The following functions no longer use `Write-Host`. Instead, they use `Write-Verbose`:
* `Disable-NtfsCompression`
* `Enable-NtfsCompression`
* `Grant-ComPermission`
* `Grant-Permission`
* `Install-Service`
* `Remove-SslCertificateBinding`
* `Revoke-ComPermission`
* Created default, table-based display formats for `System.DirectoryServices.AccountManagement.UserPrincipal`, `System.DirectoryServices.AccountManagement.GroupPrincipal`, `Microsoft.Web.Administration.ApplicationPool`, `Microsoft.Web.Administration.Site`, and `Microsoft.Web.Administration.Application` objects.
* Re-organized Carbon's internal directory structure. You shouldn't be reaching into Carbon's internals, so this shouldn't matter, but wanted to let everyone know just in case.
### New Functions
* `Clear-DscLocalResourceCache` clears the local LCM's DSC resource. This makes developing resources easier.
* `Clear-MofAuthoringMetadata` removes authoring metadata from .mof files.
* `Copy-DscResource` copies DSC resources (ZIP files, MSI archives, MOF files, etc.), including timestamps, checksums, and copying only changed files.
* `ConvertTo-SecurityIdentifer` converts a binary, string, or `System.Security.Principal.SecurityIdentifier` object into a `System.Security.Principal.SecurityIdentifier` object.
* `Get-DscError` gets any DSC errors that were written to a computer's DSC event log.
* `Get-DscWinEvent` gets DSC events that were written to a computer's DSC event log.
* `Get-FileSharePermission` gets the sharing permissions on a file/SMB share (*not* the NTFS file system permissions).
* `Get-FileShare` uses WMI to get `Win32_Share` objects for the file shares installed on the local computer.
* `Get-Group` gets a local group or all local groups.
* `Get-Msi` reads installer information and properties from an MSI file.
* `Get-PowerShellModuleInstallPath` gets the path where new module's should be installed. Beginning with PowerShell 4, modules should get installed into `$env:ProgramFiles\Windows PowerShell\Modules`. Under PowerShell 3, it is `$PSHome\Modules`. This function returns the correct location for the version of PowerShell you're using.
* `Get-User` gets a local user or all local users.
* `Initialize-Lcm` configures the DSC Local Configuration Manager on computers, including installing the private key needed for decrypting credentials.
* `Remove-GroupMember` removes a user/group from a local group. Thanks to [Philip Kluss](https://bitbucket.org/philkloose) for the contribution.
* `Resolve-Identity` converts a system, local, or domain principal name or a SID (as a `SecurityIdentifer`, string SDDL, or byte array) into its canonical representation and includes extended identity information: domain, type, and SID.
* `Start-DscPullConfiguration` starts a configuration check on a computer that is configured to use the PULL refresh mode.
* `Test-DscTargetResource` compares target resource with desired resource. Helpful when writing `Test-TargetResource` functions.
* `Test-Group` checks if a *local* group exists.
* `Test-FileShare` uses WMI to check if a file/SMB share exists on the local computer.
* `Test-TypeDataMember` tests if a type has an extended type member defined.
* `Uninstall-FileShare` uninstalls/removes a file share, if it exists.
* `Write-DscError` writes DSC `ErrorLogRecord` objects as errors.
### New DSC Resources
* `Carbon_EnvironmentVariable` creates/removes machine-level environment variables.
* `Carbon_FirewallRule` configures firewall rules.
* `Carbon_IniFile` manages the contents of INI files.
* `Carbon_Permission` configures file, directory, registry, and certificate permissions.
* `Carbon_Privilege` configures an identity's privileges.
* `Carbon_ScheduledTask` configures scheduled tasks with `schtasks.exe`.
* `Carbon_Service` configures Windows services.
### Added `PassThru` Switches
Added a `PassThru` switch to the following functions, which will return objects of the given type:
* `Grant-ComPermission`: `Carbon.Security.ComAccessRule`, representing the granted permission.
* `Grant-Permission`: `System.Security.AccessControl.AccessRule`, representing the granted permission.
* `Install-Group`: `System.DirectoryServices.AccountManagement.GroupPrincipal`, representing the group.
* `Install-IisApplication`: `Microsoft.Web.Administration.Application`, representing the application.
* `Install-IisWebsite`: `Microsoft.Web.Administration.Site`, representing the website.
* `Install-Junction`: `System.IO.DirectoryInfo`, representing new target directories and any new/updated junctions.
* `Install-Service`: `System.ServiceProcess.ServiceController`, representing the service.
* `Install-User`: `System.DirectoryServices.AccountManagement.UserPrincipal`, representing the user.
* `Set-SslCertificateBinding`: `Carbon.Certificates.SslCertificateBinding`, representing the configured binding.
### No More Console Output
The following functions no longer return the console output of the program each one runs. Instead, the output is written to the verbose stream (i.e. use the `-Verbose` switch to see it).
* `Disable-FirewallStatefulFtp`
* `Enable-FirewallStatefulFtp`
* `Install-Service`
* `Remove-SslCertificateBinding`
* `Set-SslCertificateBinding`
* `Uninstall-Service`
### Obsolete Functions and Parameters
The following functions are now obsolete. Please don't use them and stop using them if you are. They will be removed from a future major version of Carbon. You'll get warnings if you use them.
* `Complete-Job`: It's total crap. Use PowerShell's `Wait-Job` cmdlet instead.
* `Invoke-AppCmd`: Switch to Carbon's IIS functions, or use `Get-IisConfigurationSection` to get `ConfigurationElement` objects from the `Microsoft.Web.Administration` API that you can modify.
* `Resolve-NetPath`: Switch to something else. Carbon doesn't use `net.exe` anymore.
The following functions now have obsolete parameters, which will be removed from a future major version of Carbon. You'll get warnings if you use them.
* `Install-IisAppPool's` `UserName` and `Password` parameters. Use the new `Credential` parameter instead.
* `Install-Msi's` `Quiet` switch. `Install-Msi` always installs in quiet mode. Please remove usages.
* `Install-Service's` `Password` parameter. Use the new `Credential` parameter instead.
* `Install-User's` `UserName` and `Password` parameters. Use the new `Credential` parameter instead.
* `Set-RegistryKeyValue`'s `Quiet` parameter. Please remove usages.
### Renamed Functions
The following functions were renamed, but with backwards-compatible aliases in place, so you shouldn't have to change any code.
* `Invoke-WindowsInstaller` -> `Install-Msi`
* `Install-SmbShare` -> `Install-FileShare`
### Switch to System.DirectoryServices.AccountManagement API for User/Group Management
The following functions were re-written to use the `System.DirectoryServices.AccountManagement` API, introduced in .NET 3.5.
* `Add-MemberToGroup`
* `Install-Group`
* `Install-User`
* `Test-User`
* `Uninstall-User`
### Miscellaneous Changes
* `Get-IisAppPool`
* Now return all application pools installed on the local computer when called with no parameters.
* Added a default table format for `Microsoft.Web.Administration.ApplicationPool` objects.
* `Get-ProgramInstallInfo`
* Return object's `Version` property changed from an `int` to a [Version](http://msdn.microsoft.com/en-us/library/y0hf9t2e.aspx) object.
* Return object's now have `ProductCode` and `User` properties. If a program doesn't have a product code, it is set to `[Guid]::Empty`. The `User` property is only set for per-user software installs.
* `Get-ServiceConfiguration` now supports services from remote computers.
* `Grant-Permission` now only grants permissions on an object if those permissions aren't present. To preserve previous behavior, add the `-Force` switch to all `Grant-Permission` usages.
* `Install-Certificate's` `Exportable` switch is now only allowed when installing a certificate from a file. Previously, you could supply the switch when installing from an X509Certificate2 object but it was ignored.
* `Install-Group's` `Members` parameter renamed to `Member` (with backwards-compatible alias).
* Added `Credential` parameter to `Install-IisAppPool` for increased security and to follow PowerShell guidelines.
* `Install-IisVirtualDirectory` no longer deletes and re-creates existing virtual directories, but modifies existing virtual directories in place.
* `Install-IisWebsite`
* Added `SiteID` parameter tfor setting a website's IIS ID.
* No longer deletes and re-creates websites, but modifies existing websites in place. This may or may not be a breaking change in your environment.
* `Install-Msi`
* `Path` parameter now supports wildcards.
* Now only installs an MSI if it isn't already installed. To preserve the previous behavior and always install, add the `-Force` switch to all `Invoke-WindowsInstaller`\`Install-Msi` usages.
* `Install-Service`
* Now supports service startup parameters/arguments via the `ArgumentList` parameter.
* Improved error handling and messages. It now uses `net helpmsg` to get helpful error messages based on sc.exe exit codes.
* Added `Credential` parameter for increased security and to follow PowerShell guidelines.
* Added `Description` parameter for setting a service's description.
* Added `DisplayName` parameter for setting a service's display name.
* `Install-FileShare` (fka `Install-SmbShare`):
* Re-written to use WMI isntead of `net.exe`, so it no longer returns any console output.
* Modifies existing shares in place, instead of deleting and re-creating, *unless* the share's path changes. Changing a share's path requires the old share to be deleted and a new one created.
* `Install-User`
* Added `PasswordExpires` switch for creating accounts with passwords that expire.
* Added `UserCannotChangePassword` to prevent user from changing his password.
* `Remove-SslCertificateBinding` has better error handling.
* Added `SID` parameter to `Resolve-IdentityName` to resolve a SID into its identity name.
* `Set-HostsEntry's` `IPAddress` parameter is now a `System.Net.IPAddress` object. It used to be a string validated with a regular expression.
* `Set-RegistryKeyValue`:
* Added `UDWord` and `UQWord` parameters for setting registry key values to unsigned integers (i.e. integer values greater than `[int]::MaxValue` and `[long]::MaxValue`). Fixes [issue #165: Set-RegistryKeyValue rejects unsigned integers larger than [int]::MaxValue](https://bitbucket.org/splatteredbits/carbon/issues/165/set-registrykeyvalue).
* Deprecated `Quiet` switch.
* Only sets the value if the value doesn't exist or the current value is different than the desired value. Use the `Force` parameter to preserve previous behavior.
* `Test-Identity` now returns a `Carbon.Identity` object if the identity exists *and* you use the `-PassThru` switch. It used to return the identity's SID. Update scripts to use the `FullName` property to get the old return value, e.g. `Test-Identity -Name $userName -PassThru | Select-Object -Expand 'FullName'`.
* `Test-OSIs32Bit` now uses the Environment class's new [Is64BitOperatingSystem](http://msdn.microsoft.com/en-us/library/system.environment.is64bitoperatingsystem.aspx) property.
* `Test-OSIs64Bit` now uses the Environment class's new [Is64BitOperatingSystem](http://msdn.microsoft.com/en-us/library/system.environment.is64bitoperatingsystem.aspx) property.
* `Test-PowerShellIs32Bit` now uses the `Environment` class's new [Is64BitProcess](http://msdn.microsoft.com/en-us/library/system.environment.is64bitprocess.aspx) property.
* `Test-PowerShellIs64Bit` now uses the `Environment` class's new [Is64BitProcess](http://msdn.microsoft.com/en-us/library/system.environment.is64bitprocess.aspx) property.
* `Uninstall-ScheduledTask` now retries when un-installing a task fails with "The function attempted to use a name that is reserved for use by another transaction." error.
* `Unprotect-String`
* Added `AsSecureString` switch, which will return a secure string instead of a normal string.
* The `Password` parameter now accepts `SecureString` values.
* `Initialize-Lcm`
* Added support for PowerShell 5: `RefreshIntervalMinutes` default value changed to from 15 to 30; `RefreshIntervalMinutes` minimum value is now 30; `ConfigurationFrequency`'s minimum value is now 1 (from 2).
## Changes Since `alpha.26`
### Enhancements
* Includes all changes made in version 1.9.0.
* PowerShell 4 is now required. Carbon won't even import under PowerShell 3.
* Removed `Carbon_Script` resource. It only existed so I could pass values to my script blocks. Turns out, the built-in `Script` resource supports this with the `$using:` scope. Remember, your most important features is documentation!
* Created a new `Carbon_ScheduledTask` DSC resource for managing scheduled tasks.
* The `Version` property on the objects returned by `Get-ProgramInstallInfo` is now a proper .NET `Version` object instead of an integer.
### Bug Fixes
* `Carbon_Permission` DSC resource fails when assigning multiple permissions
* Grant-Permission fails when clearing multiple existing, non-inherited permission on an item.
## Changes Since `alpha.31`
### Bug Fixes
* `Set-HostsEntry` fails to preserve whitespace if existing lines end with a comment/description. Thanks to [Konstantin Ushenin](https://vk.com/kostanew) for the fix.
* Carbon's `System.ServiceProcess.ServiceController` extended type data causes errors when PowerShell formats `System.ServiceProcess.ServiceController` objects that represent services on remote computers.
* `Install-Msi` didn't properly detect when installation failed.
* `Set-EnvironmentVariable` fails to set process-level environment variable.
* `Compress-Item` doesn't remove handled errors from global error array.
* `Grant-Permission` fails with an unhelpful error message if it is unable to get the ACL on a private key.
### Enhancements
* `Import-Carbon.ps1` is more intelligent about when it tries to re-load Carbon. It will force a re-import of Carbon if any of Carbon's files have changed or the version has changed.
* Created `Uninstall-Junction` for uninstalling a junction in an idempotent way (i.e. without errors). Thanks to [Konstantin Ushenin](https://vk.com/kostanew) for the contribution.
* Improved error handling in `Remove-Junction`.
* `Install-Service`:
* Now supports service startup parameters/arguments.
* No longer returns `ServiceController` objects by default. This should improve backwards-compatability. Added a `PassThru` switch you can use to get a `ServiceController` object returned to you.
* Improved error handling. It now uses `net helpmsg` to get helpful error messages based on sc.exe exit codes.
* Improved handling of arguments/services with spaces in them under PowerShell 5.
* Added `Credential` parameter for increased security and to follow PowerShell guidelines.
* Now supports setting a service's description and display name.
* Starting the service now respects caller's error action preference. Before, `Start-Service` would write an error even if somone called `Install-Service` with an `Ignore` or `SilentlyContinue` error action preference.
* New `Test-TypeDataMember` for testing if a type has an extended type member defined.
* `Install-IisAppPool` no longer returns appcmd.exe output.
* Added `PassThru` parameter to `Install-IisAppPool` to control when a `Microsoft.Web.Administration.ApplicationPool` for the installed app pool is returned.
* `Get-ServiceConfiguration` and Carbon's extended type data for `System.ServiceProcess.ServiceController` objects now supports services from remote computers.
* `Uninstall-ScheduledTask` now retries when un-installing a task fails with "The function attempted to use a name that is reserved for use by another transaction." error.
* Added new `FileIndex`, `LinkCount`, and `VolumeSerialNumber` extended type data on `System.IO.FileInfo` objects for getting a file's index, its hard link count, and volume serial number, respectively.
* `Grant-Permission` now only returns an access rule object when the new `PassThru` switch is used. In previous 2.0 alpha releases, it only returned something when permissions on an object were added or changed.
* `Install-User` only returns a user object when the new `PassThru` switch is used. In previous 2.0 alpha releases, it only returned an object if a user was created or updated.
* `Grant-ComPermissions` only returns an access rule object when the new `PassThru` switch is used. In previous 2.0 alpha releases, it only returned an object if permissions were changed.
* `Install-IisApplication` only returns an IIS application object when the new `PassThru` switch is used. In previous 2.0 alpha releases, it only returned an object if the application was created or modified.
* Created `Get-Msi` function for reading MSI information and properties from an MSI file.
* `Carbon.Computer.ProgramInstallInfo` objects (returned from `Get-ProgramInstallInfo`) now have `ProductCode` and `User` properties. If a program doesn't have a product code, it is set to `[Guid]::Empty`. The `User` property is only set for per-user software installs.
* `Invoke-WindowsInstaller` renamed `Install-Msi`, with a backwards-compatibility-preserving alias.
* `Install-Msi` now supports wildcards for MSI path to install.
* `Install-Msi` now only installs an MSI if it isn't already installed. To preserve the previous behavior and always install, add the `-Force` switch to all `Invoke-WindowsInstaller`\`Install-Msi` usages.
* Added `SiteID` parameter to `Install-IisWebsite` for setting a website's IIS ID.
* Put the `Resolve-IdentityName` function back. It was removed from previous alpha releases.
* `Install-IisWebsite` no longer deletes and re-creates websites. This may or may not be a breaking change in your environment.
* `Install-SmbShare` no longer returns net.exe output, instead writing it to the verbose stream. To see previous output, use the `-Verbose` switch.
* Changed `-PasswordNeverExpires` switch to `PasswordExpires` on `Install-User` for improved backwards-compatability.
* `Set-SslCertificateBinding` no longer returns binding objects by default. Use new `PassThru` switch to get the old behavior.
* The product version of the Carbon assembly now includes pre-release version information, as defined by the [Semantic Versioning specification](http://semver.org). To get this version, run `Get-Item Carbon.dll | Select-Object -ExpandProperty 'VersionInfo' | Select-Object -ExpandProperty 'ProductVersion'`
* The Carbon NuGet package now supports installing and uninstalling using Chocolatey.
* Added `AsSecureString` switch to `Unprotect-String` which causes `Unprotect-String` to return a secure string instead of a normal string.
* `Unprotect-String` now accepts a `SecureString` as the value for the `Password` parameter, which is the password for the private key used to decrypt from password-protected RSA certificate file.
* Added `Credential` parameter to `Install-IisAppPool` for increased security and to follow PowerShell guidelines.
* Added `Credential` parameter to `Install-User` for increased security and to follow PowerShell guidelines.
* `Install-IisVirtualDirectory` now modifies existing virtual directories in place, instead of deleting and re-creating.
* `Invoke-AppCmd` is now obsolete and will be removed from a future version of Carbon. Switch to Carbon's IIS functions, or use `Get-IisConfigurationSection` to get `ConfigurationElement` objects from the `Microsoft.Web.Administration` API that you can modify.
* Added `Description` and `DisplayName` properties to `Carbon_Service` for setting a service's description and display name.
* `Grant-Permission` now writes an error if you don't have access to a private key. Previously, it would skip the key without any messages.
* `Resolve-Identity` now converts SIDs to a `Carbon.Identity` object. The SID may be a string (SID in SDDL form), byte array, or a `SecurityIdentifier` object.
* `Get-FileSharePermission` gets the sharing permissions on a file/SMB share (*not* the NTFS file system permissions).
* Created `Get-FileShare` function. It uses WMI to get `Win32_Share` objects for the file shares installed on the local computer.
* Renamed `Install-SmbShare` to `Install-FileShare`, with a backwards-compatible alias in place.
* Added `SID` parameter to `Resolve-IdentityName` to resolve a SID into its identity name.
* Created `ConvertTo-SecurityIdentifer` function to convert a binary, string, or `System.Security.Principal.SecurityIdentifier` object into a `System.Security.Principal.SecurityIdentifier` object.
* `Install-FileShare` (fka `Install-SmbShare`):
* Re-written to use WMI isntead of `net.exe`.
* Modifies existing shares in place, instead of deleting and re-creating, *unless* the share's path changes. Changing a share's path requires the old share to be deleted and a new one created.
* `Carbon_FirewallRule` now fails with an error if it finds multiple firewall rules with the same name.
* `Set-RegistryKeyValue`:
* Added `UDWord` and `UQWord` parameters for setting registry key values to unsigned integers (i.e. integer values greater than `[int]::MaxValue` and `[long]::MaxValue`). Fixes [issue #165: Set-RegistryKeyValue rejects unsigned integers larger than [int]::MaxValue](https://bitbucket.org/splatteredbits/carbon/issues/165/set-registrykeyvalue).
* Deprecated `Quiet` switch.
* Only sets value if the value is changed. Use the `Force` parameter to preserve previous behavior.
* `Uninstall-Service` no longer returns sc.exe stdout.
# 1.9.0 (8 November 2014)
This is the last minor release for version 1.0. Future 1.0-compatible releases will *only* contain bug fixes, no new features. It takes too much time to maintain two versions, and I'd rather spend my time getting 2.0 out the door. Carbon 2.0 will require PowerShell 4.0, so start planning.
## Enhancements
### Certificates
* Added `KeyStorageFlags` parameter to `Get-Certificate` when loading a certificate from a file for better control when storing the certificate.
### Hosts File
* `Set-HostsEntry` now handles writing to an in-use/locked hosts file, retrying up to 10 times before writing an error, waiting a random amount of time (from 0 to 1000 milliseconds) between each retry attempt.
### IIS
* `Get-IisMimeMap`, `Remove-IisMimeMap`, and `Set-IisMimeMap` now support managing MIME types for websites, virtual directories, and applications.
### Scheduled Tasks
* Created `Get-ScheduledTask` function for getting the scheduled tasks on the local computer using `schtasks.exe`.
* Created `Install-ScheduledTask` function for installing a scheduled task using `schtasks.exe`.
* Created `Test-ScheduledTask` function for testing if a scheduled tasks on the local computer exists using `schtasks.exe`.
* Created `Uninstall-ScheduledTask` function for deleting a scheduled task using `schtasks.exe`.
### Services
* `Install-Service` now supports setting a command to run when a service fails.
## Bug Fixes
### General
* `Import-Carbon` fails when `-WhatIf` switch is used.
* Importing Carbon no longer writes an error if the `PATH` environment variable contains a path to a non-existent drive (issue [#134](https://bitbucket.org/splatteredbits/carbon/issue/134/import-carbon-fails-with-path-environment)).
### INI
* `Set-IniEntry` fails when adding the first section-less setting to a file.
### Internet Explorer
* `Enable-IEActivationPermission` no longer returns the `hkcr:` drive.
### Security
* Fixed an error that occurs when setting permissions on a private key fails: the error message is created using an invalid format string (issue [#133](https://bitbucket.org/splatteredbits/carbon/issue/133/set-cryptokeysecurity-invalid-parameters)).
* Fixed an exception that gets thrown when setting a private key's permissions and the only certificate key is AT_SIGNATURE (issue [#132](https://bitbucket.org/splatteredbits/carbon/issue/132/set-cryptokeysecurity-throws-exception)).
### Services
* `Install-Service` stops Windows service even when no settings/configuration has changed (fixes issue [#131](https://bitbucket.org/splatteredbits/carbon/issue/131/install-service-always-restarts-service)).
* `Install-Service` didn't clear services depended on during a re-install.
* `Install-Service` wasn't restarting a manual service if it was running when configuration began.
* `Uninstall-Service` hard codes the path to the Windows directory (fixes issue [#143](https://bitbucket.org/splatteredbits/carbon/issue/143/uninstall-service-script-has-hard-coded)). Thanks to [Travis Mathison](https://bitbucket.org/tdmathison) for the fix.
# 1.8.0 (7 September 2014)
## Enhancements
### General
* The following functions now write messages with `Write-Verbose` instead of `Write-Host`. See [Write-Host Considered Harmful](http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/).
* `Add-GroupMember`
* `Clear-TrustedHost`
* `Convert-XmlFile`
* `Disable-FirewallStatefulFtp`
* `Disable-IEEnhancedSecurityConfiguration`
* `Disable-IisSecurityAuthentication`
* `Disable-NtfsCompression`
* `Enable-FirewallStatefulFtp`
* `Enable-IEActivationPermission`
* `Enable-IisSecurityAuthentication`
* `Enable-NtfsCompression`
* `Grant-ComPermission`
* `Grant-MsmqMessageQueuePermission`
* `Grant-Permission`
* `Grant-ServiceControlPermission`
* `Install-Group`
* `Install-IisApplication`
* `Install-MsmqMessageQueue`
* `Install-PerformanceCounter`
* `Install-RegistryKey`
* `Install-Service`
* `Install-User`
* `Install-WindowsFeature`
* `Invoke-WindowsInstaller`
* `Lock-IisConfigurationSection`
* `New-Junction`
* `Protect-Acl`
* `Remove-IniEntry`
* `Remove-Junction`
* `Remove-SslCertificateBinding`
* `Reset-HostsFile`
* `Reset-MsmqQueueManagerID`
* `Revoke-ComPermission`
* `Revoke-ServicePermission`
* `Set-IisHttpHeader`
* `Set-IisMimeMap`
* `Set-IisWebsiteID`
* `Set-IisWindowsAuthentication`
* `Set-IniEntry`
* `Set-RegistryKeyValue`
* `Set-SslCertificateBinding`
* `Uninstall-IisAppPool`
* `Uninstall-WindowsFeature`
* `Unlock-IisConfigurationSection`
* The following internal functions (which we warned you not to use!) are no longer exported:
* Add-IisServerManagerMember
* Get-IdentityPrincipalContext
* Invoke-ConsoleCommand
* ConvertTo-ProviderAccessControlRights
* Assert-WindowsFeatureFunctionsSupported
* Resolve-WindowsFeatureName
### Certificates
* Improving error handling when `Get-Certificate` fails to load a certificate from a file.
* `Install-Certificate` now supports installing with an `X509Certificate2` object instead of just a path to a certificate.
* `Remove-SslCertificateBinding`: improved error handling.
* `Set-SslCertificateBinding`: improved error handling.
* Improved documentation for `Get-Certificate`.
* Added extended script property `StoreName` to `X509Store` objects to return the store's `System.Security.Cryptography.X509Certificates.StoreName` value.
* Added a table view/format for `X509Store` objects. PowerShell's default view is a list, so you'll have to explicitly format the objects as a table, e.g. `dir cert:\LocalMachine | Format-Table`.
* `Get-Certificate`'s `Path` parameter now supports wildcards and certificate provider paths, e.g. `cert:\`.
* `Get-Certificate` now writes an error if a certificate isn't found when getting a certificate by its path.
### Computer
* Created `Get-ProgramInstallInfo` function to get the information displayed by the `Programs and Features` UI.
### Cryptography
* `Protect-String` can now encrypt strings as a specific user. Use the `Credential` parameter.
* Created `New-RsaKeyPair` for creating public/private RSA key pair using `makecert.exe` and `pkv2pfx.exe`. Requires that you've installed a Windows SDK.
* `Protect-String` can now encrypt strings using an RSA public key.
* `Unprotect-String` can now decrypt strings using an RSA private key.
### File System
* `Disable-NtfsCompression`: improved error handling.
* `Enable-NtfsCompression`: improved error handling.
* Created `Compress-Item` function for compressing files/directories into a ZIP file.
* Created `Test-ZipFile` function for testing if a file is a ZIP file.
* Created `Expand-Item` function for decompressing a ZIP file.
* `New-TempDirectory` now supports adding a prefix to the temporary directory's name, so you can more easily track down those scripts/processes that don't clean up after themselves.
### Firewall
* `Disable-FirewallStatefulFtp`: improved error handling.
* Added `Name` and `LiteralName` parameters to `Get-FirewallRule` to return specific rules instead of all of them.
* `Get-FirewallRule`, now returns `Carbon.Firewall.Rule` objects, instead of anonymous hashes.
* Added default table format for `Get-FirewallRule` output.
* `Get-FirewallRule` now returns additional rule information: interface type, security, source, description, program, and service. Who knew `netsh advfirewall firewall rule show` had a `verbose` switch? RTFM.
### INI
* `Remove-IniEntry` now handles case-sensitive INI files.
* `Set-IniEntry` now handles case-sensitive INI files.
* `Split-Ini` now handles case-sensitive INI files.
### MSI
* `Invoke-WindowsInstaller`: improved error message if installation fails.
### Security
* Creating `Revoke-Permission` function for revoking a user's permission to a file, directory, registry key, or certificate's private key/key container.
* Creating `ConvertTo-ContainerInheritanceFlags` function for converting `System.Security.AccessControl.InheritanceFlags` and `System.Security.AccessControl.PropagationFlag` values into a `Carbon.Security.ContainerInheritanceFlags` value.
* `Get-Permission` now supports returning the permissions on private keys/key containers.
* `Grant-Permission` now supports granting permissions on private keys//key containers.
* `Test-Permission` now supports testing permissions on certificate private keys/key containers.
### Services
* Created `Get-ServiceConfiguration` function for loading a service's configuration: description, account name/username, failure actions, etc.
* Added the following extended type data to `System.ServiceController.Service`:
* Description
* ErrorControl
* FailureProgram
* FirstFailure
* LoadOrderGroup
* Path
* RebootDelay
* RebootDelayMinutes
* RebootMessage
* ResetPeriod
* ResetPeriodDays
* RestartDelay
* RestartDelayMinutes
* SecondFailure
* StartMode
* StartType
* TagID
* ThirdFailure
* UserName
## Bug Fixes
### General
* Importing Carbon gives an error if `PATH` environment variable contains an empty path.
* Improved the error handling in the following functions so they properly catch exceptions and write friendlier errors:
* `Get-Certificate`
* `Grant-Privilege`
* `Revoke-Privilege`
### Certificates
* `Get-Certificate` couldn't open CA/CertificateAuthority store (fixes issue [#130](https://bitbucket.org/splatteredbits/carbon/issue/130/get-certificate-doesnt-find-any)).
* Extended script property `DisplayName` on `X509Store` objects returning wrong store name for custom stores, now returns an empty string.
### File System
* `Disable-NtfsCompression` now *really* supports multiple paths.
* `Enable-NtfsCompression` now *really* supports multiple paths.
### Path
* `Resolve-PathCase` didn't work under Windows 2012 R2.
### Users and Groups
* The `Carbon.Identity.FindByName` method and the `Resolve-IdentityName` and `Test-Identity` functions now handle identity names with `.` for the domain/machine name, e.g. `.\Administrator`.
* The `Carbon.Identity.FullName` property returns the wrong value when domain is empty/null, e.g. `Resolve-IdentityName -Name 'Everyone'` returns `\Everyone`, when it should return `Everyone`.
* The `Carbon.Identity.FindByName` method and the `Resolve-IdentityName` and `Test-Identity` functions unable to resolve `LocalSystem` account (which is actually `NT AUTHORITY\SYSTEM`).
# 1.7.0 (30 April 2014)
There is now [a Carbon support mailing list](https://groups.google.com/forum/#!forum/carbonps).
## Enhancements
### General
* Import-Carbon.ps1 now supports the `-WhatIf` switch.
* Import-Carbon.ps1 now hides verbose log messages when removing/importing Carbon even when supplying the `-Verbose` switch because I think the verbose output is too verbose and not helpful at all.
* Import-Carbon.ps1 now supports adding a prefix when importing the Carbon module (with the `Prefix` parameter) to avoid name collisions and [follow best practices](http://blogs.msdn.com/b/powershell/archive/2014/04/07/what-s-in-a-name-using-the-ps-prefix.aspx).
### Certificates
* `Get-CertificateStore` now supports non-standard, custom certificate stores.
* `Get-Certificate` now supports non-standard, custom certificate stores.
* `Install-Certificate` now supports non-standard, custom certificate stores.
* `Uninstall-Certificate` now supports non-standard, custom certificate stores.
## Bug Fixes
### General
* No more silent errors when importing Carbon on Windows 2012 R2.
### Certificates
* `Get-Certificate` no longer writes a silent error when a certificate does not exist. Instead, no error is written.
### File System
* `Install-Junction` fails when target path is hidden.
* `Test-NtfsCompression` fails when file/directory is hidden.
* `Test-PathIsJunction` fails when tested directory is hidden.
### Security
* `Grant-Permission` fails when item is hidden.
* `Grant-Permission` doesn't handle non-existent paths, causing cascading errors.
* `Test-Permission` always returns `$false` when testing leaf-level permissions and the `ApplyTo` parameter is provided, i.e. it doesn't ignore inheritance/propagation flags on leaves.
# 1.6.0 (1 February 2014)
## Bug Fixes
### Certificates
* `Get-Certificate` fails when passed a relative path.
* `Install-Certificate` fails when passed a relative path.
### File System
* `Remove-Junction` doesn't delete a junction when given a relative path to the junction.
### Services
* `Install-Service` doesn't properly resolve a service's path.
### Shares
* Fixed `Install-SmbShare` example to use correct syntax. [#111.](https://bitbucket.org/splatteredbits/carbon/issue/111)
## Enhancements
### Hosts File
* Created `Remove-HostsEntry` function for removing hostnames from a hosts file.
### IIS
* Created `Join-IisVirtualPath` for joining paths used by the IIS APIs.
* Renamed all IIS `Path` parameters which represented virtual paths to `VirtualPath` (with backwards-compatible aliases):
* `Disable-IisSecurityAuthentication`
* `Enable-IisDirectoryBrowsing`
* `Enable-IisSecurityAuthentication`
* `Enable-IisSsl`
* `Get-IisApplication`
* `Get-IisConfigurationSection`
* `Get-IisHttpHeader`
* `Get-IisHttpRedirect`
* `Get-IisMimeMap`
* `Get-IisSecurityAuthentication`
* `Set-IisHttpHeader`
* `Set-IisHttpRedirect`
* `Set-IisWindowsAuthentication`
* `Test-IisConfigurationSection`
* `Test-IisSecurityAuthentication`
* Renamed `Get-IisWebsite`'s `SiteName` parameter to `Name` (with a backwards-compatible alias).
* Renamed all IIS `Name` parameters which represented virtual paths to `VirtualPath` (with backwards-compatible aliases):
* `Install-IisApplication`
* `Install-IisVirtualDirectory`
* Renamed all IIS `Path` parameters which represented physical paths to `PhysicalPath` (with backwards-compatible aliases):
* `Install-IisApplication`
* `Install-IisVirtualDirectory`
* `Install-IisWebsite`
### .NET
* Created `Test-DotNet` for testing if v2 or v4 of the .NET framework is installed.
### Path
* Created `Get-PathProvider` function for getting a path's PowerShell provider.
### PowerShell
* Updated `Invoke-PowerShell` to test if the appropriate .NET framework is installed if the user chooses an explicit runtime to use.
### Security
* Created `Test-Permission` function for checking if a user/group has a set of permissions and, optionally, a set of inheritance and propagation flags on a file, directory, or registry key.
* `Test-Permission` now automatically includes the `Synchronize` permission when checking for exact permissions, since this permission is always on and can never be removed from a file/directory.
### Services
* `Install-Service` no longer requires a password, in order to support [managed service accounts and virtual accounts](http://technet.microsoft.com/en-us/library/dd548356.aspx). We have no idea if this works, since we can't test locally. Please let us know if this fix works for you. [#114](https://bitbucket.org/splatteredbits/carbon/issue/114)
### Users and Groups
* Updated `Install-User` to support passwords longer than 14 characters. Thanks to [James Crowley](http://www.jamescrowley.co.uk/) for the fix.
### Windows Features
* Marked Assert-WindowsFeatureFunctionsSupported as an internal function. Please don't use. It will be removed from future versions of PowerShell.
* Updated `Test-WindowsFeature` to work on Windows 8/2012.
* Created new `Carbon.Identity` class for representing identities. It also contains a static `FindByName` method which uses The Windows `LookupAccountName` function to find full account names, domains, and sids.
* Updated `Test-Identity` to use `[Carbon.Identity]::FindByName` to find identities so it no longer throws exceptions when an identity can't be found.
* Updated `Resolve-IdentityName` to use `[Carbon.Identity]::FindByName` to find identities so it no longer throws exceptions when an identity can't be found.
# 1.5.1 (3 October 2013)
## Bug Fixes
### IIS
* `Set-IisWebsiteID` wasn't consistently starting a website after changing its ID.
### Shares
* `Install-SmbShare` has an unused variable which uses an undefined variable to create its value. When running in strict mode, PowerShell writes an error about using the undefined variable. Removed the unused variable.
# 1.5.0 (6 September 2013)
## Enhancements
### IIS
* `Set-IisWebsiteID` now attempts to start a website whose ID has changed, since IIS stops a website whenever its ID changes.
### Network
* Added `Get-IPAddress` function for getting the IPv4/IPv6 addresses currently in use on the local computer's network interfaces.
* Added `Test-IPAddress` function for testing if an IP address is in use on one the local computer's network interfaces.
### Path
* Added `Test-UncPath` function for testing if a path is a UNC or not.
### PowerShell
* `Invoke-PowerShell` now runs script blocks in PowerShell 3 under a v2.0 CLR.
### Shares
* `Install-SmbShare` now creates the share's directory if it doesn't exist.
## Bug Fixes
### Certificates
* `Get-Certificate` throws an exception and halts script execution when loading a certificate file with a private key and the user doesn't have permission to write to Windows' MachineKeys directory. It now writes an error instead.
### PowerShell
* `Invoke-PowerShell` doesn't run under a v2.0 CLR when using parameters `-Runtime 'v2.0'`.
# 1.4.0 (10 August 2013)
## Enhancements
### File System
* Created `Install-Junction` function for creating new and/or updating existing junctions. This is a more idempotent way of creating junctions, as opposed to `New-Junction` and `Remove-Junction` which report errors if a junction already exists or doesn't exist, respectively.
### IIS
* Objects returned by `Get-IisWebsite` now have a dynamic `PhysicalPath` script property, so you don't have to traverse down into the default application's default virtual directory object to get it.
* `Install-IisApplication`, `Install-IisWebsite`, and `Install-IisVirtualDirectory` now canonicalize physical paths, i.e. they convert any path with a relative part (e.g. '..') to a full path. It turns out IIS doesn't like paths with relative parts.
* Created `Get-IisApplication` function to get `Microsoft.Web.Administration.Application` objects for all or specific applications under a website.
* `Install-IisApplication` now uses the `Microsoft.Web.Administration` API instead of `appcmd.exe`.
### PowerShell
* Added `ExecutionPolicy` parameter to `Invoke-PowerShell` to allow setting a custom exeuction policy when using `Invoke-PowerShell` to run a script.
## Bug Fixes
### IIS
* `Install-IisApplication` not updating/changing physical path on existing application.
### .NET
* `Set-DotNetAppSetting` and `Set-DotNetConnectionString` failed if setting .NET configuration under an architecture where the PowerShell execution policy doesn't allow running scripts.
# 1.3.0 (8 July 2013)
## Enhancements
### PowerShell
* `Invoke-PowerShell` now supports running an external script.
* Added `OutputFormat` argument to `Invoke-PowerShell` so your scripts/script blocks can return XML results instead of plain text.
* Renamed `Invoke-PowerShell`'s `Args` parameter to `ArgumentList` (with backwards compatibile `Args` alias).
* Renamed `Invoke-PowerShell`'s `Command` parameter to `ScriptBlock` (with backwards-compatible `Command` alias).
* `Invoke-PowerShell` now runs 64-bit PowerShell from 32-bit PowerShell.
* `Get-PowerShellPath` now returns path for 64-bit PowerShell when running 32-bit PowerShell.
### Text
* Created new `ConvertTo-Base64` function for encoding strings in base-64.
* Created new `ConvertFrom-Base64` function for decoding base-64 strings.
## Bug Fixes
### .NET
* `Set-DotNetAppSetting` and `Set-DotNetConnectionString` weren't able to set .NET 2.0 app settings and connections string when running under PowerShell 3.
# 1.2.0 (25 June 2013)
## Enhancements
### General
* Carbon should now work under PowerShell v3.0!
### Certificates
* Added support for IPv6 addresses to `Get-SslCertificateBinding`, `Remove-SslCertificateBinding`, and `Set-SslCertificateBinding`.
### .NET
* Added `ProviderName` parameter to `Set-DotNetConnectionString` for setting a connection string's `providerName` attribute/value.
### File System
* Created `Disable-NtfsCompression` function for disabling NTFS compression on files/directories.
* Created `Enable-NtfsCompression` function for enabling NTFS compression on files/directories.
* Created `Test-NtfsCompression` function for testing if NTFS compression is enabled on a file/directory.
### IIS
* The [site object](http://msdn.microsoft.com/en-us/library/microsoft.web.administration.site.aspx) returned by `Get-IisWebsite` now as a `CommitChanges` method so you can persist modifications you make to the site.
* `Get-IisWebsite` now returns all websites if no `SiteName` is given.
* Created `Set-IisWebsiteID` function for explicitly setting a website's ID.
### INI
* Created `Remove-IniEntry` function for removing entries/settings from an INI file.
### Performance Counters
* `Install-PerformanceCounter` now supports installing a base performance counter. Thanks to Philip Teilmeier for the contribution.
* `Install-PerformanceCounter`'s `Description` parameter is now optional.
### PowerShell
* `Invoke-PowerShell` now defaults to running under the current CLR, instead of defaulting to a v2.0 CLR. This makes upgrading to PowerShell v3.0 easier.
* `Invoke-PowerShell` now writes an error and returns if running PowerShell v3.0 and you want to run under a v2.0 CLR. Unfortunately, PowerShell v3.0 requires .NET 4.0, so you can't run anything on an earlier CLR.
### Privileges
* `Revoke-Privilege` now supports case-insensitive privilege names.
* Updated `Grant-Privilege` to better handle when passing a privilege name with the wrong case.
* Updated `Grant-Privilege` documentation to make it clear privilege names are case-sensitive.
### XML
* New `Convert-XmlFile`, for transforming an XML file with Microsoft's XDT (XML Data Transformation) technology. Thanks to Mark Sargent for the contribution.
## Bug Fixes
### General
* Deleted the obsolete variable `$CarbonImported`. Carbon no longer exports any of its variables.
### Certificates
* `Get-SslCertificateBinding` can't parse bindings to IPv6 addresses.
### Performance Counters
* `Install-PerformanceCounter` couldn't be used to create counters that used/required a base counter. Thanks to Philip Teilmeier for the contribution.
# 1.1.0 (1 April 2013)
## Upgrade Instructions
* On Windows 2008 R2, custom identies that run IIS app pools need the `SeBatchLogonRight`. `Install-IisAppPool` now grants this privilege on all operating systems. If this won't work in your environment, you can remove these privileges with `Revoke-Privilege`.
## Enhancements
### General
* Fixed some typos and ommissions in the v0.5.0.1 and v0.5.0.0 sections of the release notes.
* Updated `Import-Carbon.ps1` script to import Carbon regardless of the name of the directory Carbon is installed in.
### Certificates
* Added `IssuedTo` and `IssuedBy` properties to [X509Certificate2](http://msdn.microsoft.com/en-us/library/ms148409(v=vs.90).aspx) objects. The values match what the Certificates MMC snap-in displays.
* Added `DisplayName` property to [X509Store](http://msdn.microsoft.com/en-us/library/d228271e(v=vs.90).aspx) objects, to show the names of the stores as they are displayed in the Certificates MMC snap-in.
### Computer
* Created `Resolve-NetPath` for getting the path to the Windows `net.exe` command/application. Updated all functions that call `net.exe` to use this function to resolve its path. Thanks to Paul Aage Aasheim for discovering that when running login scripts, `net.exe` isn't in the path.
### IIS
* Created `Get-IisHttpHeader` for getting the custom HTTP headers for a website or one of its sub-directories.
* Created `Set-IisHttpHeader` for creating/setting a custom HTTP header for a website or one of its sub-directories.
* Created `Get-IisMimeMap` for getting the file extension to MIME type mappings for the IIS web server.
* Created `Remove-IisMimeMap` for removing a file extension to MIME type mapping for the IIS web server.
* Created `Set-IisMimeMap` for creating/setting a file extension to MIME type mapping for the IIS web server.
* When creating an app pool that runs under a custom, non-service account, `Install-IisAppPool` grants that user the `SeBatchLogonRight`.
* `Install-IisAppPool` writes an error if its user account doesn't exist (i.e. if the value of the `Username` parameter doesn't exist).
### Privileges
* Improved exception handling in `Grant-Privilege` and `Revoke-Privilege`.
* `Grant-Privilege` and `Revoke-Privilege` now write an error message if an identity doesn't exist.
## Bug Fixes
### Computer
* `Install-SmbShare` can't find `net.exe` when running as part of a Windows logon script. Thanks to Paul Aage Aasheim for identifying and reporting this bug. All usages of the `net.exe` application were updated to use the new `Resolve-NetPath` function, which get the path to `net.exe` without assuming it is in the user's `PATH` environment variable.
### Users and Groups
* `Test-Identity` no longer writes an error if it can't find a fully-qualified local user, e.g. `$env:COMPUTERNAME\Username`.
# 1.0.0 (6 March 2013)
## Upgrade Instructions
* Remove the `Quiet` parameter from calls to the `Import-Carbon.ps1` script.
* If you're nesting Carbon as a sub-module of another module, ***STOP***. This causes havoc. Create an `Import-*.ps1` script for your module which imports Carbon before importing your own module. Update your scripts to import your module with your fancy new `Import-*.ps1` script. See [Best Practices for Importing PowerShell Modules](http://pshdo.com/archive/2012/6/4/best-practices-for-importing-powershell-modules.html) for details.
## Enhancements
### General
* The `Import-Carbon.ps1` script no longer checks if Carbon is a sub-module of another module, so the `Quiet` parameter was removed. ***Please don't nest Carbon in your modules!*** It will cause havoc.
* `Import-Carbon.ps1` will no longer stop execution if an error occurs during an import (i.e. the `$ErrorActionPreference = 'Stop'` line was removed).
### IIS
* Added `Test-IisWebsiteExists` alias for `Test-IisWebsite`, for backwards-compatibility with earlier releases.
### Security
* Added `Unprotect-AclAccessRules` alias for `Protect-Acl`, for backwards-compatibility with earlier releases.
* Added rename of `Unprotect-AclAccessRules` to `Protect-Acl` to v0.5.0.0 section of release notes.
### Services
* Renamed `Install-Service`'s `Dependencies` parameter to `Dependency` (with backwards-compatible alias), to follow PowerShell naming standards.
### Users and Groups
* `Install-User`: you can now set a user's full name with the optional `FullName` parameter.
## Bug Fixes
### Security
* `Grant-Permission` returns boolean values to the pipeline when clearing access rules.
### Service
* `Install-Service` fails if `Dependency` parameter doesn't have a value. Sometimes.
### Shares
* `Install-SmbShare` fails if a principal name contains a space.
### Users and Groups
* `Add-GroupMember` doesn't handle when the .NET Active Directory throws an exception when adding members to a group, causing script termination.
# 0.5.0.1 (9 January 2013)
## Enhancements
### Active Directory
* Renamed `Format-ADSpecialCharacters` to `Format-ADSearchFilterValue`, with backwards-compatible alias.
### Certificates
* Renamed `Get-SslCertificateBindings` to `Get-SslCertificateBinding`, with backwards-compatible alias.
* Added `Remove-Certificate` alias for `Uninstall-Certificate`, for backwards-compatibility with earlier releases.
### COM
* Renamed `Get-ComPermissions` to `Get-ComPermission`, with backwards-compatible alias.
* Renamed `Grant-ComPermissions` to `Grant-ComPermission`, with backwards-compatible alias.
* Renamed `Revoke-ComPermissions` to `Revoke-ComPermission`, with backwards-compatible alias.
### Firewall
* Renamed `Get-FirewallRules` to `Get-FirewallRule`, with backwards-compatible alias.
### IIS
* Renamed `Add-IisServerManagerMembers` to `Add-IisServerManagerMembers`, with backwards-compatible alias.
* Added `StatusCode` alias for `Set-IisHttpRedirect's` `HttpResponseStatus` parameter, for backwards-compatibility with earlier releases.
* Added `Test-IisAppPoolExists` alias for `Test-IisAppPool`, for backwards-compatibility with earlier releases.
* Added `Remove-IisWebsite` alias for `Uninstall-IisWebsite`, for backwards-compatibility with earlier releases.
### Internet Explorer
* Renamed `Enable-IEActivationPermissions` to `Enable-IEActivationPermission`, with backwards-compatible alias.
### MSMQ
* Renamed `Grant-MsmqMessageQueuePermissions` to `Grant-MsmqMessageQueuePermission`, with backwards-compatible alias.
* Added `Remove-MsmqMessageQueue` alias for `Uninstall-MsmqMessageQueue`, for backwards-compatibility with earlier releases.
### Path
* Added `ConvertTo-FullPath` alias for `Resolve-FullPath`, for backwards-compatibility with earlier releases.
* Added `Get-PathCanonicalCase` alias for `Resolve-PathCase`, for backwards-compatibility with earlier releases.
### Performance Counters
* Renamed `Get-PerformanceCounters` to `Get-PerformanceCounter`, with backwards-compatible alias.
### PowerShell
* Renamed `Add-TrustedHosts` to `Add-TrustedHost`, with backwards-compatible alias.
* Renamed `Add-TrustedHost`'s `Entries` parameter to `Entry`, with backwards-compatible alias.
* Renamed `Clear-TrustedHosts` to `Clear-TrustedHost`, with backwards-compatible alias.
* Renamed `Complete-Jobs` to `Complete-Job`, with backwards-compatible alias.
* Renamed `Complete-Job`'s `Jobs` parameter to `Job`, with backwards-compatible alias.
* Renamed `Get-TrustedHosts` to `Get-TrustedHost`, with backwards-compatible alias.
* Renamed `Set-TrustedHosts` to `Set-TrustedHost`, with backwards-compatible alias.
* Renamed `Set-TrustedHost`'s `Entries` parameter to `Entry`, with backwards-compatible alias.
### Security
* Renamed `Assert-AdminPrivileges` to `Assert-AdminPrivilege`, with backwards-compatible alias.
* Renamed `ConvertTo-InheritanceFlags` to `ConvertTo-InheritanceFlag`, with backwards-compatible alias.
* Renamed `ConvertTo-InheritanceFlag`'s `ContainerInheritanceFlags` parameter to `ConvertTo-InheritanceFlag`, with backwards-compatible alias.
* Renamed `ConvertTo-PropagationFlags` to `ConvertTo-PropagationFlag`, with backwards-compatible alias.
* Renamed `ConvertTo-PropagationFlag`'s `ContainerInheritanceFlags` parameter to `ConvertTo-InheritanceFlag`, with backwards-compatible alias.
* Renamed `Get-Permissions` to `Get-Permission`, with backwards-compatible alias.
* Renamed `Grant-Permissions` to `Grant-Permission`, with backwards-compatible alias.
* Renamed `Grant-Permission`'s `Permissions` parameter to `Permission`, with backwards-compatible alias.
* Renamed `Test-AdminPrivileges` to `Test-AdminPrivilege`, with backwards-compatible alias.
### Service
* Renamed `Get-ServicePermissions` to `Get-ServicePermission`, with backwards-compatible alias.
* Added `Remove-Service` alias for `Uninstall-Service`, for backwards-compatibility with earlier releases.
### Users and Groups
* Renamed `Add-GroupMembers` to `Add-GroupMember`, with backwards-compatible alias.
* Renamed `Add-GroupMember`'s `Members` parameter to `Member`.
* Added `Remove-User` alias for `Uninstall-User`, for backwards-compatibility with earlier releases.
### Windows Features
* Added `Install-WindowsFeatures` alias for `Install-WindowsFeature`, for backwards-compatibility with earlier releases.
* Added `Features` alias for `Install-WindowsFeature's` `Name` parameter, for backwards-compatibility with earlier releases.
* Added `Uninstall-WindowsFeatures` alias for `Uninstall-WindowsFeature`, for backwards-compatibility with earlier releases.
* Added `Features` alias for `Uninstall-WindowsFeature's` `Name` parameter, for backwards-compatibility with earlier releases.
# 0.5.0.0 (7 January 2013)
## Upgrade Instructions
This release contains many backwards incompatible changes. We apologize for this inconvenience. We are making these changes so we can get ready for the v1.0 release. One of our goals for v1.0 is to get the functions and their interfaces internally consistent and consistent with PowerShell naming schemes. Once v1.0 is out the door, backwards-incompatible changes will be phased in as much as possible.
Take the following steps to get your scripts to work with this release.
### Certificates
Replaces usages of:
* `Get-SslCertificateBindings` with `Get-SslCertificateBinding`
* `Get-SslCertificateBinding -IPPort '0.0.0.0:443'` with `Get-SslCertificateBinding`
* `Get-SslCertificateBinding -IPPort '10.1.1.1:8001` with `Get-SslCertificateBinding -IPAddress '10.1.1.1' -Port 8001`
* `Test-SslCertificateBinding -IPPort '0.0.0.0:443` with `Test-SslCertificateBinding`
* `Test-SslCertificateBinding -IPPort '10.1.1.1:8001` with `Test-SslCertificateBinding -IPAddress '10.1.1.1' -Port 8001`
* `Set-SslCertificateBinding -IPPort '0.0.0.0:443` with `Set-SslCertificateBinding`
* `Set-SslCertificateBinding -IPort '1.2.3.4:8001' with `Set-SslCertificateBinding -IPAddress '1.2.3.4' -Port 8001
* `Remove-SslCertificateBinding -IPPort '0.0.0.0:443` with `Remove-SslCertificateBinding`
* `Remove-SslCertificateBinding -IPPort '10.1.1.1:8001` with `Remove-SslCertificateBinding -IPAddress '10.1.1.1' -Port 8001`
### Computer
Replace usages of
* `Set-EnvironmentVariable -Scope 'Process'` with `Set-EnvironmentVariable -ForProcess`
* `Set-EnvironmentVariable -Scope 'User'` with `Set-EnvironmentVariable -ForUser`
* `Set-EnvironmentVariable -Scope 'ForComputer'` with `Set-EnvironmentVariable -ForComputer`
* `Remove-EnvironmentVariable -Scope 'Process'` with `Remove-EnvironmentVariable -ForProcess`
* `Remove-EnvironmentVariable -Scope 'User'` with `Remove-EnvironmentVariable -ForUser`
* `Remove-EnvironmentVariable -Scope 'ForComputer'` with `Remove-EnvironmentVariable -ForComputer`
### Cryptography
* `Protect-String -Scope CurrentUser` with `Protect-String -ForUser`
* `Protect-String -Scope LocalMachine` with `Protect-String -ForComputer`
### IIS
* Renamed the `StatusCode` property on the object returned by `Get-IisHttpRedirect` to `HttpResponseStatus`. Update usages accordingly.
* The `Bindings` property returned by `Get-IisWebsite` is now a collection of `Microsoft.Web.Administration.Binding` objects. Update usages of `$site.Bindings[$idx].IPAddress` and `$site.Bindings[$idx].Port` to `$site.Bindings[$idx].Endpoint.Address` and `$site.Bindings[$idx].Endpoint.Port`, respectively.
Replace usages of:
* `Set-IisAnonymousAuthentication` with `Enable-IisSecurityAuthentication -Anonymous`
* `Set-IisAnonymousAuthentication -Disabled` with `Disable-IisSecurityAuthentication -Anonymous`
* `Set-IisBasicAuthentication` with `Enable-IisSecurityAuthentication -Basic`
* `Set-IisBasicAuthentication -Disabled` with `Disable-IisSecurityAuthentication -Basic`
* `Set-IisWindowsAuthentication` with `Enable-IisSecurityAuthentication -Windows` and `Set-IisWindowsAuthentication -DisableKernelMode`
* `Set-IisWindowsAuthentication -UseKernelMode` with `Set-IisWindowsAuthentication`
* `Set-IisWindowsAuthentication -Disabled` with `Disable-IisSecurityAuthentication -Windows`
* `Unlock-IisConfigSection -Name <string>` with `Unlock-IisConfigurationSection -SectionPath <string>` (run `appcmd.exe lock config -section:?` for values to the new `SectionPath` parameter)
* `Unlock-IisBasicAuthentication` with `Unlock-IisConfigurationSection -SectionPath 'system.webServer/security/authentication/basicAuthentication'`
* `Unlock-IisCgi` with `Unlock-IisConfigurationSection -SectionPath 'system.webServer/cgi'`
* `Unlock-IisWindowsAuthentication` with `Unlock-IisConfigurationSection -SectionPath 'system.webServer/security/authentication/windowsAuthentication'`
### INI
Replace usages of:
* `Split-Ini -Path <string>` with `Split-Ini -Path <string> -AsHashtable` (hashtable is no longer returned by default)
* `Split-Ini -Path <string> -PassThru` with `Split-Ini -Path <string>` (per-line objects are now returned by default)
### Path
Replace usages of
* `Get-PathRelativeTo -To <string> -From <string>'` with `Resolve-RelativePath -Path <string> -FromDirectory <string>`
* `Get-PathRelativeTo -To <string> -From <string> -FromType 'File'` with `Resolve-RelativePath -Path <string> -FromFile <string>`
### Performance Counters
* `Get-PerformanceCounters` no longer returns an empty list if there are zero counters or a single element list if there is one counter. It now returns `null` and a single object, respectively. Update usages accordingly.
### PowerShell
* `Get-TrustedHosts` no longer returns an empty list if there are no trusted hosts. It now return nothing/`null`. Update usages accordingly.
### Security
* `Assert-AdminPrivileges` now returns `True` or `False` if the user doesn't have admin privileges. It also no longer throws an exception, but writes an error. If you want to preserve current behavior where it stops script execution, replace usages with `Assert-AdminPrivileges -ErrorAction Stop`.
### Shares
Replace usages of:
* `Install-Share -Permissions '"ShareAdmins,FULL"','"ShareWriters,CHANGE"','"ShareReaders,READ"'` with `Install-SmbShare -FullAccess ShareAdmins -ChangeAccess ShareWriters -ReadAccess ShareReaders`.
### Windows Features
Replace usages of:
* `Test-WindowsFeature` with `Test-WindowsFeature -Installed`
* `Install-WindowsFeatureIis` with `Install-WindowsFeature -Iis`
* `Install-WindowsFeatureIis -HttpRedirection` with `Install-WindowsFeature -Iis -IisHttpRedirection`
* `Install-WindowsFeatureMsmq` with `Install-WindowsFeature -Msmq`
* `Install-WindowsFeatureMsmq -HttpSupport` with `Install-WindowsFeature -Msmq -MsmqHttpSupport`
* `Install-WindowsFeatureMsmq -ActiveDirectoryIntegration` with `Install-WindowsFeature -MsmqActiveDirectoryIntegration`
## New Features
### IIS
* Created `Get-IisConfigurationSection` function for getting a site's (and optional sub-directory's) [Microsoft.Web.Administration.ConfigurationSection](http://msdn.microsoft.com/en-us/library/microsoft.web.administration.configurationsection(v=vs.90).aspx) objects for an arbitrary IIS configuration section.
* Created `Get-IisSecurityAuthentication` function for getting a site's (and optional sub-directory's) [anonymous, basic, digest, or Windows authentication configuration section](http://msdn.microsoft.com/en-us/library/microsoft.web.administration.configurationsection(v=vs.90).aspx).
* Created `Test-IisSecurityAuthentication` function for testing if anonymous, basic, digest, or Windows authentication is enabled for a website (and optional sub-directory).
* Created `Get-IisConfigurationSection` function for returning an arbitrary IIS configuration section using the Microsoft.Web.Administration API.
* Created `Lock-IisConfigurationSection` function for locking arbitrary global IIS configuration sections.
* Created `Test-IisConfigurationSection` function for testing if an configuration section exists or is locked or not.
* Created function `Get-IisAppPool` for getting a `Microsoft.Web.Administration.AppPool` object for an application pool.
* Created function `Uninstall-IisAppPool` for removing an IIS application pool.
### Windows Features
* Created new `Get-WindowsFeature` function for getting a list of available Windows features.
## Bug Fixes
### Service
* `Install-Service` not granting default service identity, Network Service, the correct permissions.
* `Install-Service` not correctly resolving local identity account names.
## Enhancements
### Certificates
* Moved functionality of `Get-SslCertificateBinding` into `Get-SslCertificateBindings`. Can now filter by `IPAddress` and/or `Port`.
* `Get-SslCertificateBindings` now returns `Carbon.Certificates.SslCertificateBinding` objects. All information displayed by the `netsh http show sslcert` command is returned as part of those objects.
* `Get-SslCertificateBindings` now supports filtering by `IPAddress` and `Port` separately, instead of requiring both. The old `IPPort` parameter is replaced with `IPAddress` and `Port` parameters.
* `Test-SslCertificateBinding` now supports testig by `IPAddress` and `Port` separately, instead of requiring both. The old `IPPort` parameter is replaced with `IPAddress` and `Port` parameters.
* Replaced `IPPort` parameter on `Get-SslCertificateBinding` with separate `IPAddress` and `Port` parameters on `Get-SslCertificateBindings`. Set `IPAddress` only if you want to bind to a specific IP address (i.e. *not* 0.0.0.0). Set `Port` if *not* binding to port 443.
* Replaced `IPPort` parameter on `Remove-SslCertificateBinding` with separate `IPAddress` and `Port` parameters. Set `IPAddress` only if you want to remove a binding for a specific IP address (i.e. *not* 0.0.0.0). Set `Port` if the binding is *not* on port 443.
* Renamed `Remove-Certificate` to `Uninstall-Certificate` (added backwards-compatible alias in v0.5.0.1).
### Computer
* Replaced the `Scope` parameter on `Set-EnvironmentVariable` and `Remove-EnvironmentVariable` with scope-specific `ForProcess`, `ForUser`, and `ForComputer` switches.
### Cryptography
* Replaced `Protect-String`'s `Scope` parameteter with the `ForUser` or `ForComputer` scope-specific switches.
### Hosts File
* `Set-HostsEntry` no longer throws an exception if the hosts file contains an invalid line. Instead, a warning is written and the line is commented out.
### INI
* `Split-Ini` now returns strongly-typed `Carbon.Ini.IniNode` objects instead of hashtables.
* The line numbers returned by `Split-Ini` start at 1 instead of 0.
* `Split-Ini` now returns name/value objects by default (the `PassThru` switch is no longer needed for this behaviro). This makes it more PowerShell-y. The old behavior of returning a `Hashtable` is available be using the new `AsHashtable` switch.
### IIS
* Replaced `Set-IisAnonymousAuthentication` with `Enable-IisSecurityAuthentication` and `Disable-IisSecurityAuthentication`.
* Replaced `Set-IisBasicAuthentication` with `Enable-IisSecurityAuthentication` and `Disable-IisSecurityAuthentication`.
* Moved code to enable/disable Windows authentication from `Set-IisWindowsAuthentication` to `Enable-IisSecurityAuthentication` and `Disable-IisSecurityAuthentication`.
* Switched the default behavior of `Set-IisWindowsAuthentication` to enable kernel mode. To disable kernel mode, use the `DisableKernelMode` switch.
* Renamed `Unlock-IisConfigSection` to `Unlock-IisConfigurationSection`.
* Removed `Unlock-IisConfigurationSection`'s `Name` parameter and replaced it with `SectionPath`, which takes a list of full path to the configuration section(s) to unlock.
* Removed `Unlock-IisBasicAuthentication` in favor of `Unlock-IisConfigurationSection -SectionPath 'system.webServer/security/authentication/basicAuthentication'`.
* Removed `Unlock-IisCgi` in favor of `Unlock-IisConfigurationSection -SectionPath 'system.webServer/cgi'`.
* Removed `Unlock-IisWindowsAuthentication` in favor of `Unlock-IisConfigurationSection -SectionPath 'system.webServer/security/authentication/windowsAuthentication'`.
* Renamed `Remove-Service` to `Uninstall-Service` (added backwards-compatible alias in v0.5.0.1).
* `Install-Service` writes errors instead of throwing exceptions.
* `Install-Service` grants `ReadAndExecute` file system permissions on the service executable to the service identity instead of `FullControl`.
* Improved `Install-Service`'s `WhatIf` support.
* Renamed `Test-IisAppPoolExists` to `Test-IisAppPool` (added backwards-compatible alias in v0.5.0.1).
* Renamed `Remove-IisWebsite` with `Uninstall-IisWebsite` (added backwards-compatible alias in v0.5.0.1).
* `Install-IisAppPool` now always sets the application pool to run as the system's default application pool identity if the `ServiceAccount` parameter isn't given.
* `Install-IisAppPool` now starts an IIS application pool if it is stoppped.
* `Get-IisHttpRedirect` now returns a `Carbon.Iis.HttpRedirectConfigurationSection` object. The `StatusCode` property on the old object is now named `HttpResponseStatus`.
* Renamed the `StatusCode` parameter on `Set-IisHttpRedirect` to `HttpResponseStatus` (added backwards-compatible alias in v0.5.0.1).
* `Get-IisWebsite` now returns a `Microsoft.Web.Administration.Site` object.
### MSMQ
* Renamed `Remove-MsmqMessageQueue` to `Uninstall-MsmqMessageQueue` (added backwards compatible alias in v0.5.0.1).
### Path
* Renamed `Get-PathRelativeTo` to `Resolve-RelativePath`. Renamed its `To` parameter to `Path`, and moved it to position 0. Replaced/combined the `From` and `FromType` parameters with `FromDirectory` and `FromFile` parameters.
* Renamed `ConvertTo-FullPath` to `Resolve-FullPath` (added backwards-compatible alias in v0.5.0.1). Added support for converting unrooted paths using the current location.
* Renamed `Get-PathCanonicalCase` with `Resolve-PathCase` (added backwards-compatible alias in v0.5.0.1). Added support for piping in `Get-Item` and `Get-ChildItem` output, e.g. `Get-Item C:\WINDOWS | Resolve-PathCase` returns C:\Windows.
### Performance Counters
* `Get-PerformanceCounters` now returns nothing/`null` or a single object instead of an empty/single element array when there are no or one performance counters.
* `Install-PerformanceCounter` no longer re-installs a counter if a counter with its name, description, and type already exist.
### PowerShell
* `Get-TrustedHosts` now returns nothing/`null` if there are no trusted hosts. (It used to return an empty array.)
### Security
* `Assert-AdminPrivileges` no longer throws an exception if the user doesn't have administrative privileges. Instead, it writes an error and returns `False`. It returns `True` if the user has privileges.
* Renamed `Unprotect-AclAccessRules` to `Protect-Acl` (added backwards-compatible alias in v1.0.0).
### Shares
* Replaced the `Permissions` parameter on `Install-SmbShare` with `FullAccess`, `ChangeAccess`, and `ReadAccess` parameters. Previously, to set share permissions, you passed in specially-formatted values to the `Permission` parameter, e.g. `"MyGroup,FULL","MyOtherGroup,READ"`. Now, just pass a list of identity name(s) to the `FullAccess`, `ChangeAccess`, or `ReadAccess` parameters to grant those identies full, change, or read access, e.g. `-FullAccess MyGroup -ReadAccess MyOtherGroup`.
### Users and Groups
* Renamed `Remove-User` to `Uninstall-User` (added backwards-compatible alias in v0.5.0.1).
### Windows Features
* `Test-WindowsFeature` now tests if a Windows feature exists, instead of if it is installed. Added an `Installed` switch to detect if a feature exists *and* if it is installed.
* Renamed `Install-WindowsFeatures` to `Install-WindowsFeature` (added backwards-compatible alias in v0.5.0.1).
* Renamed `Install-WindowsFeature`'s `Features` parameter to `Name` (added backwards-compatible alias in v0.5.0.1).
* Removed `Install-WindowsFeatureIis` and replaced with `Iis` and `IisHttpRedirection` switches on `Install-WindowsFeature`.
* Removed `Install-WindowsFeatureMsmq` and replaced with `Msmq`, `MsmqHttpSupport`, and `MsmqActiveDirectoryIntegration` switches on `Install-WindowsFeature`.
* Renamed `Uninstall-WindowsFeatures` to `Uninstall-WindowsFeature` (added backwards-compatible alias in v0.5.0.1).
* Renamed `Uninstall-WindowsFeature`'s `Features` parameter to `Name` (added backwards-compatible alias in v0.5.0.1).
* Added `Iis`, `IisHttpRedirection`, `Msmq`, `MsmqHttpSupport`, and `HttpActiveDirectoryIntegration` switches to `Uninstall-WindowsFeature`.
* `Install-WindowsFeature`, `Test-WindowsFeature`, and `Uninstall-WindowsFeature` are now available even if the current operating system doesn't support managing Windows features. They don't do anything in those situations, but they exist.
* `Install-WindowsFeature`, `Test-WindowsFeature`, and `Uninstall-WindowsFeature` are not available if the PowerShell v3.0 server manager cmdlets exists (on Windows 8/2012).
### Miscellaneous
* Replaced all instances where functions were throwing exceptions with `Write-Error`.
* The Carbon assembly is now versioned and signed.
# 0.4.0.1 (18 December 2012)
## Bug fixes
* `Enable-IisSsl` not setting SSL flags correctly when requiring client certificates.
# 0.4.0.0 (17 November 2012)
## Upgrade Instructions
* If you install a manual or disabled Windows service with `Install-Service`, you now have to call `Start-Service` yourself. `Install-Service` only starts services whose startup type is set to `Automatic` (which is the default).
* We've stopped distributing Microsoft's `subinacl.exe` program. We didn't have permission to distribute. Plus its no longer supported. If any of your scripts used `Invoke-SubInAcl`, you'll want to [download `subinacl.exe` yourself](http://www.microsoft.com/en-us/download/details.aspx?id=23510) and copy `Invoke-SubInAcl` before upgrading (you can find it in the Carbon directory in the `Services.ps1` file.
* If you're using `Grant-Permission` without named parameters, the `Path` parameter moved from position 3 to position 1. Re-order your parameters accordingly.
* Rename usages of `Set-IisDirectoryBrowsing` to `Enable-IisDirectoryBrowsing`. If you use named parameters, rename its `Directory` paremter to `Path`.
* Replace usages of `Set-HgrcDefaultPushUrl` with `Set-IniEntry` instead, e.g. `Set-IniEntry -Path 'Path\to\repo\.hg\hgrc' -Section paths -Name 'default.push' -Value 'DefaultPushUrl'`
* Rename usages of `Get-FullPath` with `ConvertTo-FullPath`.
## Enhancements
* Created `Get-Privileges`, `Grant-Privilege`, `Revoke-Privilege`, and `Test-Privilege` for managing an identity's security operation privileges.
* `Install-Service` now uses `Grant-Privilege` to grant custom service identities the `SeServiceLogonRight` privilege. This replaces usage of Microsoft's legacy [ntrights.exe](http://support.microsoft.com/kb/315276), which we probably didn't have permission to distribute.
* Created `Get-ServicePermissions` function for getting the permissions for a service, i.e. what users can control a service.
* Created `Assert-Service` function to write an error if a service doesn't exist.
* Created `Get-ServiceAcl` function to get the discretionary access control list (DACL) for a service.
* Created `Get-ServiceSecurityDescriptor` function to get the raw security descriptor for a service.
* Created `Grant-ServicePermission` function to grant service control permissions to an identity.
* Created `Revoke-ServicePermission` function to revoke all of an identity's permissioms to control a service.
* Created `Set-ServiceAcl` function to set a service's discretionary access control list (DACL).
* Created `Test-Service` function to check if a service exists *without* writing an error.
* Removed `Invoke-SubInAcl` function and the `subinacl.exe` program. Use the `Grant-ServicePermission` and `Revoke-ServicePermission` functions instead. If you still need `subinacl.exe`, please [download it from Microsoft](http://www.microsoft.com/en-us/download/details.aspx?id=23510).
* `Grant-Permissions` now supports controlling inheritance and propagation flags via the `ApplyTo` parameter, which should be a value of the new `Carbon.Security.ContainerInheritanceFlags` enumeration, which encapsualtes all the valid combinations of inheritance/propagation flags. See the help for `Grant-Permissions` for more information. Thanks to Jonathan Valdez for the feature request and initial code.
* Created `ConvertTo-InheritanceFlags` function for converting a `Carbon.Security.ContainerInheritanceFlags` to the necessary/applicable `System.Security.AccessControl.InheritanceFlags`.
* Created `ConvertTo-PropagationFlags` function for converting a `Carbon.Security.ContainerInheritanceFlags` to the necessary/applicable `System.Security.AccessControl.PropagationFlags`.
* Created `Get-Permissions` function for getting the non-inherited permissions on a file, directory, registry key, or registry value with the ability to return a specific identity's permissions and/or inherited permissions.
* Renamed `Set-IisDirectoryBrowsing` to `Enable-IisDirectoryBrowsing` and renamed its `Directory` parameter to `Path`.
* Removed `Set-HgrcDefaultPushUrl`. Use `Set-IniEntry` instead.
* Renamed `Test-IisWebsiteExists` to `Test-IisWebsite` to adhere to PowerShell naming conventions (added backwards-compatible alias in v1.0.0).
* Renamed `Get-FullPath` to `ConvertTo-FullPath` to adhere to PowerShell naming conventions.
## Bug fixes
* `Install-Service` no longer tries to start a service if its `StartupType` is set to `Manual` or `Disabled`.
* `Path` is now the first parameter to `Grant-Permissions` (it was the third) to match PowerShell standards/patterns.
* `Find-ADUser` writes an error and returns null instead of throwing an exception.
# 0.3.1.0 (29 October 2012)
## Enhancements
* Improved `Disable-IEEnhancedSecurityConfiguration` and `Enable-IEActivationPermissions` for enabling Internet Explorer to run headless by non-priveleged users.
* Changed the way `Invoke-WindowsInstaller` waits for MSI to finish installing: instead of searching for any MSI process, it now searches for an MSI process that is a child of the current PowerShell process.
* Simplified how `Add-GroupMembers` adds group members.
* The version number in the module manifest now gets updated correctly for each release. You should now be able to tell what version you're running by looking in `Carbon\Carbon.psd1`, or, if Carbon is imported in your console, running `Get-Module Carbon | Select-Object Version`.
* Created `Get-ComPermissions` function for getting COM Access or Launch and Activation Permissions. These are the permissions you see in Component Services (i.e. dcomcnfg) when you right-click `My Computer`, select `Properties`, click the `COM Security` tab then click the `Edit Default..` or `Edit Limits...` buttons under **Access Permissions** or **Launch and Activation Permissions**, respectively.
* Created `Grant-ComPermissions` for granting COM Access and/or Launch and Activation permissions.
* Created `Revoke-ComPermissions` for revoking COM Access and/or Launch and ACtivation permissions.
* Created `Test-Identity` function for testing if user or group exists on the local computer or in a domain.
* Created `Resolve-IdentityName` function for determinig a user/group's canonical name. For example, it converts `Administrators` into `BUILTIN\Administrators`.
* Improved the way the Windows Features functions detect the best way to manage Windows features. The old way would write an error to the error stream, which bubbled up at weird times and made diagnosing real errors harder.
* Added a `Quiet` parameter to `Set-RegistryKeyValue` so that `Write-Host` output is muffled.
* Created `Reset-MsmqQueueManagerID` function, which resets MSMQ's Queue Manager ID.
# 0.3.0 (28 September 2012)
## Upgrade Instructions
This release contains backwards-**incompatible** changes to the following functions:
* `Set-IisSslFlags`
* `Set-TrustedHosts`
* `Invoke-PowerShell`
### Set-IisSslFlags
This function was renamed to `Enable-IisSsl`. Its `Enable128BitSsl` parameter was renamed to `Require128BitSsl`.
Configuring client certificates is now a little stricter/clearer. You can no longer specify both `AcceptClientCertificates` and `RequireClientCertificates`. Also, if you specify `RequireClientCertificates`, you must now also supply the `RequireSsl` switch (before, setting the `RequireClientCertificates` switch implicitly set the `RequireSsl` switch).
### Set-TrustedHosts
Make sure you're not calling `Set-TrustedHosts` with an empty array/value for the `Entries` parameter. The function now throw an error in that situation. If you need to clear the list of trusted hosts, use `Clear-TrustedHosts`.
### Invoke-PowerShell
If you call `Invoke-PowerShell` without the `x86` switch and PowerShell is 32-bit, you'll get an error. Under Windows x64, 32-bit PowerShell can't start the 64-bit instance because Windows redirects all access from C:\Windows\system32 to C:\Windows\SysWOW64. If anyone knows how to get around this, let me know!
## Enhancements
* Renamed `Set-IisSslFlags` to `Enable-IisSsl` to better reflect what it does. Also, created parameter sets around client certificate settings so you can't configure them incorrectly. ([Fixes #25: Set-IisSslFlags: Create parameter sets to accurately reflect what flags are allowed to be set simultaneously.](https://bitbucket.org/splatteredbits/carbon/issue/25/set-iissslflags-create-parameter-sets-to))
* Added `WhatIf` support to `Install-MsmqMessageQueue`.
* Created new `Clear-TrustedHosts` for clearing PowerShell's trusted hosts list.
## Bug Fixes
* Rename `Enable-IisSsl/Set-IisSslFlags's` `Enable128BitSsl` parameter to `Require128BitSsl`] ([Fix #24 Set-IisSslFlags: Rename the Enable128BitSsl parameter to Require128BitSsl](https://bitbucket.org/splatteredbits/carbon/issue/24/set-iissslflags-rename-the-enable128bitssl)).
* [Fix issue #19](https://bitbucket.org/splatteredbits/carbon/issue/19/install-iisapppool-doesnt-change-an): `Install-IisAppPool` doesn't change an existing 32-bit app pool to be a 64-bit app pool.
* [Fix issue #33](https://bitbucket.org/splatteredbits/carbon/issue/33/install-msmqmessagequeue-can-wait-forever): `Install-MsmqMessageQueue`: Can wait forever for a queue to get created. It now waits 10 seconds.
* [Fix issue #36](https://bitbucket.org/splatteredbits/carbon/issue/36/get-powershellpath-returns-the-wrong-path): `Get-PowerShellPath` returns the wrong path when running x86 PowerShell on x64 computers.
* [Fix issue #37](https://bitbucket.org/splatteredbits/carbon/issue/37/invoke-powershell-should-write-an-error): `Invoke-PowerShell` should write an error when running as x86 on Windows x64 without the x86 flag (i.e. 32-bit PowerShell can't launch a 64-bit PowerShell, so throw an error in that situation).
* [Fix issue #38](https://bitbucket.org/splatteredbits/carbon/issue/38/set-trustedhosts-passing-an-empty-value): `Set-TrustedHosts`: passing an empty value for the Entries parameter clears the hosts list. The `Entries` parameter is now required. To clear the trusted hosts list, use `Clear-TrustedHosts`.
# 0.2.7 (3 September 2012)
## Enhancements
* New functions for working with the registry:
* `Get-RegistryKeyValue`: Get a value from a registry key.
* `Install-RegistryKey`: Create a new registry key.
* `Remove-RegistryKeyValue`: Remove a value from a registry key.
* `Set-RegistryKeyValue`: Set/create a value in a registry key.
* `Test-RegistryKeyValue`: Test if a value exists in a registry key.
* `Unprotect-AclAccessRules`: Turns off inherited access rules on an item in the file system or registry.
* Added a `Clear` parameter to the `Grant-Permissions` function for clearing any non-inherited permissions on a file system/registry item.
# 0.2.6 (30 June 2012)
## Enhancements
* Improved documentation for:
* `Grant-ServiceControlPermission`
* `Install-Service`
* `Invoke-SubInAcl`
* `Remove-Service`
* `Restart-RemoteService`
* `Install-Share`
* `Add-GroupMembers`
* `Get-WmiLocalUserAccount`
* `Install-Group`
* `Install-User`
* `Remove-User`
* `Test-User`
* `Install-WindowsFeatureIis`
* `Install-WindowsFeatureMsmq`
* `Install-WindowsFeatures`
* `Test-WindowsFeature`
* `Uninstall-WindowsFeatures`
* `Assert-FirewallConfigurable`
* `Disable-FirewallStatefulFtp`
* `Enable-FirewallStatefulFtp`
* `Get-FirewallRules`
* `Test-FirewallStatefulFtp`
* `Find-ADUser`
* `Format-ADSpecialCharacters`
* `Get-Certificate`
* `Get-CertificateStore`
* `Set-HgrcDefaultPushUrl`
* Help files and example scripts now included in Carbon download package.
* Added test to help ensure all functions have proper documentation.
## Bug fixes
* `Install-IisWebsite` now validates website bindings
# 0.2.5 (29 June 2012)
## Enhancements
* Improved documentation for:
* `Test-IisAppPool`
* `Test-IisWebsiteExists`
* `Unlock-IisBasicAuthentication`
* `Unlock-IisCgi`
* `Unlock-IisConfigSection`
* Import-Carbon.ps1
* `Set-IniEntry`
* `Split-Ini`
* `Set-HgrcDefaultPushUrl`
* `Get-MsmqMessageQueue`
* `Get-MsmqMessageQueuePath`
* `Grant-MsmqMessageQueuePermissions`
* `Install-Msmq`
* `Install-MsmqMessageQueue`
* `Remove-MsmqMessageQueue`
* `Test-MsmqMessageQueue`
* `Get-PerformanceCounters`
* `Install-PerformanceCounter`
* `Test-PerformanceCounter`
* `Test-PerformanceCounterCategory`
* `Uninstall-PerformanceCounterCategory`
* `Complete-Jobs`
* `Get-PowershellPath`
* `Invoke-PowerShell`
* `Test-PowerShellIs32Bit`
* `Test-PowerShellIs64Bit`
* `Add-TrustedHosts`
* `Get-TrustedHosts`
* `Set-TrustedHosts`
* `Assert-AdminPrivileges`
* `Convert-SecureStringToString`
* `Grant-Permissions`
* `New-Credential`
* `Test-AdminPrivileges`
* Improved whitespace in HTML documentation code samples.
# 0.2.4 (28 June 2012)
## Enhancements
* Improved documentation for:
* Get-PathCanonicalCase
* Get-PathRelativeTo
* New-Junction
* New-TempDir
* Remove-Junction
* Test-PathIsJunction
* Reset-HostsFile
* Set-HostsEntry
* Add-IisDefaultDocument
* Get-IisHttpRedirect
* Get-IisVersion
* Get-IisWebsite
* Install-IisApplication
* Install-IisAppPool
* Install-IisVirtualDirectory
* Install-IisWebsite
* Invoke-AppCmd
* Remove-IisWebsite
* Set-IisAnonymousAuthentication
* Set-IisBasicAuthentication
* Set-IisDirectoryBrowsing
* Set-IisHttpRedirect
* Set-IisSslFlags
* Set-IisWebsiteSslCertifiate
* Set-IisWindowsAuthentication
# 0.2.3 (27 June 2012)
## Enhancements
* Improved documentation for:
* Disable-IEEnhancedSecurityConfiguration
* Enable-IEActivationPermissions
* Get-FullPath
* Invoke-WindowsInstaller
* Protect-String
* Remove-EnvironmentVariable
* Set-DotNetAppSetting
* Set-DotNetConnectionString
* Set-EnvironmentVariable
* Test-OSIs32Bit
* Test-OSIs64Bit
* Unprotect-String
## Bug fixes
* Invoke-WindowsInstaller doesn't validate that installer path ends in '.msi'.
* Invoke-WindowsInstaller not showing correct exit code when installation fails.
# 0.2.2 (19 June 2012)
## Enhancements
* Created Import-Carbon script to help users properly import Carbon.
## Bug fixes
* Add-GroupMembers fails to add Administrators and ANONYMOUS LOGON built-in accounts.
* Add-GroupMembers fails when adding built-in accounts multiple times.
* Add-GroupMembers fails to add domain user to a local group.
# 0.2.1 (28 April 2012)
* Added IsJunction property to DirectoryInfo objects. Returns true if a directory is a junction/reparse point.
* Created a Carbon assembly for compiled code. Moved P/Invoke functions from FileSystem.ps1 into assembly. This is a backwards compatible change.
* Created a Carbon.IO.JunctionPoint helper class for creating/removing/getting junction/reparse points. Updated New-Junction and Remove-Junction to use the new helper class.
* Added TargetPath property to DirectoryInfo objects. If the directory is a junction/reparse points, returns the path to the junction's target. Otherwise, $null.
# 0.2.0 (4 April 2012)
## Enhancements
* fix issue #3: Added -Runtime switch to Invoke-PowerShell function for running PowerShell under .NET 2.0 or 4.0. Valid values are 'v2.0' (for .NET 2) and 'v4.0' (for .NET 4).
* **BREAKING CHANGE:** Added -Clr2 and -Clr4 switches to Set-DotNetAppSetting and Set-DotNetConnectionString functions for modifying the .NET 2 and/or 4 machine.config files. One or both of these parameters is required.
## Bug fixes
* Improved documentation for Get-ADDomainController, Get-ADUser, Format-ADSpecialCharacters, Get-Certificate, Invoke-PowerShell, Set-DotNetAppSetting, and Set-DotNetConnectionString functions.
* fix issue #2: Get-PowerShellPath Returns Wrong Value on x86 Systems
# 0.1.0 (2 April 2012):
* First packaged release.
<#
.SYNOPSIS
Chocolately install script for Carbon.
#>
[CmdletBinding()]
param(
)
#Requires -Version 4
Set-StrictMode -Version 'Latest'
$ErrorActionPreference = 'Stop'
$env:PSModulePath -split ';' |
Join-Path -ChildPath 'Carbon' |
Where-Object { Test-Path -Path $_ -PathType Container } |
Rename-Item -NewName { 'Carbon{0}' -f [IO.Path]::GetRandomFileName() } -PassThru |
Remove-Item -Recurse -Force
jQuery( document ).ready(function() {
jQuery("#CommandsMenu > li").click( function() {
var selectedLi = jQuery("#CommandsMenu li.selected")
selectedLi.removeClass("selected");
var selectedCmdID = selectedLi.attr("id").replace("MenuItem","");
jQuery("#" + selectedCmdID).hide();
var li = jQuery(this);
li.addClass("selected");
var id = li.attr( 'id' )
id = id.replace('MenuItem','');
jQuery('#' + id).show();
return false;
});
});
/*! jQuery v2.1.4 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b="length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function qa(){}qa.prototype=d.filters=d.pseudos,d.setFilters=new qa,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function ra(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){
return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ba=/<([\w:]+)/,ca=/<|&#?\w+;/,da=/<(?:script|style|link)/i,ea=/checked\s*(?:[^=]|=\s*.checked.)/i,fa=/^$|\/(?:java|ecma)script/i,ga=/^true\/(.*)/,ha=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ia={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ia.optgroup=ia.option,ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead,ia.th=ia.td;function ja(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function ka(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function la(a){var b=ga.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function ma(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function na(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function oa(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pa(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=oa(h),f=oa(a),d=0,e=f.length;e>d;d++)pa(f[d],g[d]);if(b)if(c)for(f=f||oa(a),g=g||oa(h),d=0,e=f.length;e>d;d++)na(f[d],g[d]);else na(a,h);return g=oa(h,"script"),g.length>0&&ma(g,!i&&oa(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(ca.test(e)){f=f||k.appendChild(b.createElement("div")),g=(ba.exec(e)||["",""])[1].toLowerCase(),h=ia[g]||ia._default,f.innerHTML=h[1]+e.replace(aa,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=oa(k.appendChild(e),"script"),i&&ma(f),c)){j=0;while(e=f[j++])fa.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(oa(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&ma(oa(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(oa(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!da.test(a)&&!ia[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(aa,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(oa(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(oa(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&ea.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(oa(c,"script"),ka),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,oa(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,la),j=0;g>j;j++)h=f[j],fa.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(ha,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qa,ra={};function sa(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function ta(a){var b=l,c=ra[a];return c||(c=sa(a,b),"none"!==c&&c||(qa=(qa||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qa[0].contentDocument,b.write(),b.close(),c=sa(a,b),qa.detach()),ra[a]=c),c}var ua=/^margin/,va=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wa=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)};function xa(a,b,c){var d,e,f,g,h=a.style;return c=c||wa(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),va.test(g)&&ua.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function ya(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),f.removeChild(c),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var za=/^(none|table(?!-c[ea]).+)/,Aa=new RegExp("^("+Q+")(.*)$","i"),Ba=new RegExp("^([+-])=("+Q+")","i"),Ca={position:"absolute",visibility:"hidden",display:"block"},Da={letterSpacing:"0",fontWeight:"400"},Ea=["Webkit","O","Moz","ms"];function Fa(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Ea.length;while(e--)if(b=Ea[e]+c,b in a)return b;return d}function Ga(a,b,c){var d=Aa.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Ha(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ia(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wa(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xa(a,b,f),(0>e||null==e)&&(e=a.style[b]),va.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Ha(a,b,c||(g?"border":"content"),d,f)+"px"}function Ja(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",ta(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xa(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fa(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Ba.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fa(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xa(a,b,d)),"normal"===e&&b in Da&&(e=Da[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?za.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Ca,function(){return Ia(a,b,d)}):Ia(a,b,d):void 0},set:function(a,c,d){var e=d&&wa(a);return Ga(a,c,d?Ha(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=ya(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xa,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ua.test(a)||(n.cssHooks[a+b].set=Ga)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wa(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Ja(this,!0)},hide:function(){return Ja(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Ka(a,b,c,d,e){return new Ka.prototype.init(a,b,c,d,e)}n.Tween=Ka,Ka.prototype={constructor:Ka,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Ka.propHooks[this.prop];return a&&a.get?a.get(this):Ka.propHooks._default.get(this)},run:function(a){var b,c=Ka.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Ka.propHooks._default.set(this),this}},Ka.prototype.init.prototype=Ka.prototype,Ka.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Ka.propHooks.scrollTop=Ka.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Ka.prototype.init,n.fx.step={};var La,Ma,Na=/^(?:toggle|show|hide)$/,Oa=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pa=/queueHooks$/,Qa=[Va],Ra={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Oa.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Oa.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sa(){return setTimeout(function(){La=void 0}),La=n.now()}function Ta(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ua(a,b,c){for(var d,e=(Ra[b]||[]).concat(Ra["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Va(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||ta(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Na.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?ta(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ua(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wa(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xa(a,b,c){var d,e,f=0,g=Qa.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=La||Sa(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:La||Sa(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wa(k,j.opts.specialEasing);g>f;f++)if(d=Qa[f].call(j,a,k,j.opts))return d;return n.map(k,Ua,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xa,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Ra[c]=Ra[c]||[],Ra[c].unshift(b)},prefilter:function(a,b){b?Qa.unshift(a):Qa.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xa(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pa.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Ta(b,!0),a,d,e)}}),n.each({slideDown:Ta("show"),slideUp:Ta("hide"),slideToggle:Ta("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(La=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),La=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Ma||(Ma=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Ma),Ma=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Ya,Za,$a=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Za:Ya)),
void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Za={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$a[b]||n.find.attr;$a[b]=function(a,b,d){var e,f;return d||(f=$a[b],$a[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$a[b]=f),e}});var _a=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_a.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ab=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ab," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ab," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ab," ").indexOf(b)>=0)return!0;return!1}});var bb=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cb=n.now(),db=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var eb=/#.*$/,fb=/([?&])_=[^&]*/,gb=/^(.*?):[ \t]*([^\r\n]*)$/gm,hb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ib=/^(?:GET|HEAD)$/,jb=/^\/\//,kb=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lb={},mb={},nb="*/".concat("*"),ob=a.location.href,pb=kb.exec(ob.toLowerCase())||[];function qb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function rb(a,b,c,d){var e={},f=a===mb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function sb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function tb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function ub(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:ob,type:"GET",isLocal:hb.test(pb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":nb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?sb(sb(a,n.ajaxSettings),b):sb(n.ajaxSettings,a)},ajaxPrefilter:qb(lb),ajaxTransport:qb(mb),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=gb.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||ob)+"").replace(eb,"").replace(jb,pb[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=kb.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===pb[1]&&h[2]===pb[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(pb[3]||("http:"===pb[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),rb(lb,k,b,v),2===t)return v;i=n.event&&k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!ib.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(db.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=fb.test(d)?d.replace(fb,"$1_="+cb++):d+(db.test(d)?"&":"?")+"_="+cb++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+nb+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=rb(mb,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=tb(k,v,f)),u=ub(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var vb=/%20/g,wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&").replace(vb,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Bb=0,Cb={},Db={0:200,1223:204},Eb=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Cb)Cb[a]()}),k.cors=!!Eb&&"withCredentials"in Eb,k.ajax=Eb=!!Eb,n.ajaxTransport(function(a){var b;return k.cors||Eb&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Bb;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Cb[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Db[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Cb[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Fb=[],Gb=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Fb.pop()||n.expando+"_"+cb++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Gb.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Gb.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Gb,"$1"+e):b.jsonp!==!1&&(b.url+=(db.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Fb.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Hb=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Hb)return Hb.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Ib=a.document.documentElement;function Jb(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Jb(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Ib;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ib})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Jb(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=ya(k.pixelPosition,function(a,c){return c?(c=xa(a,b),va.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Kb=a.jQuery,Lb=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Lb),b&&a.jQuery===n&&(a.jQuery=Kb),n},typeof b===U&&(a.jQuery=a.$=n),n});
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="help -> documentation.html" stopProcessing="true">
<match url="^help/?$" />
<action type="Redirect" url="documentation.html" redirectType="Permanent" />
</rule>
<rule name="help/index.html -> documentation.html" stopProcessing="true">
<match url="^help/index.html$" />
<action type="Redirect" url="documentation.html" redirectType="Permanent" />
</rule>
<rule name="help/*.html -> *.html" stopProcessing="true">
<match url="^help/(.+\.html)$" />
<action type="Redirect" url="{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Log in or click on link to see number of positives.
- Microsoft.Web.XmlTransform.dll (cae1f260e08a) - ## / 67
- Ionic.Zip.dll (37c70e73717f) - ## / 67
- carbon.2.2.0.nupkg (c7f6d6ba8dfc) - ## / 57
- Carbon.dll (11fb3896f5d5) - ## / 57
- Carbon.Iis.dll (aca5a7f9f527) - ## / 57
- Carbon.Xdt.dll (c458e1bebbaa) - ## / 57
In cases where actual malware is found, the packages are subject to removal. Software sometimes has false positives. Moderators do not necessarily validate the safety of the underlying software, only that a package retrieves software from the official distribution point and/or validate embedded software against official distribution point (where distribution rights allow redistribution).
Chocolatey Pro provides runtime protection from possible malware.
Add to Builder | Version | Downloads | Last Updated | Status |
---|---|---|---|---|
Carbon 2.10.2 | 136829 | Wednesday, March 17, 2021 | Approved | |
Carbon 2.9.4 | 19650 | Tuesday, December 8, 2020 | Approved | |
Carbon 2.9.3 | 7069 | Wednesday, November 18, 2020 | Approved | |
Carbon 2.9.2 | 51087 | Friday, January 17, 2020 | Approved | |
Carbon 2.9.1 | 35127 | Friday, November 1, 2019 | Approved | |
Carbon 2.9.0 | 21353 | Thursday, September 19, 2019 | Approved | |
Carbon 2.8.1 | 68380 | Tuesday, March 26, 2019 | Approved | |
Carbon 2.5.0 | 79349 | Sunday, June 18, 2017 | Approved | |
Carbon 2.4.1 | 11749 | Tuesday, February 21, 2017 | Approved | |
Carbon 2.4.0 | 6709 | Wednesday, November 9, 2016 | Approved | |
Carbon 2.3.0 | 1947 | Thursday, September 29, 2016 | Approved | |
carbon 2.2.0 | 2450 | Thursday, May 12, 2016 | Approved | |
carbon 2.1.1 | 1130 | Thursday, February 25, 2016 | Approved | |
carbon 2.1.0 | 519 | Tuesday, February 9, 2016 | Approved | |
carbon 2.0.1 | 1324 | Tuesday, October 20, 2015 | Approved | |
carbon 2.0.0 | 482 | Sunday, October 11, 2015 | Approved | |
Carbon 1.9.0.20150125 | 3088 | Monday, January 26, 2015 | Approved | |
Carbon 1.9.0.1 | 373 | Sunday, January 25, 2015 | Approved | |
Carbon 1.9 | 737 | Wednesday, January 14, 2015 | Approved |
Copyright 2011 - 2016 Aaron Jensen.
Enhancements
- Aded a
LiteralPath
parameter toTest-PathIsJunction
for testing paths that contain wildcard characters (e.g.[
,]
, etc.). Remove-Junction
now supports removing multiple junctions with wildcards.- Added a
LiteralPath
parameter toRemove-Junction
for deleting junctions whose paths contain wildcard characters (e.g.[
,]
, etc.). - Added a
LiteralPath
parameter toUninstall-Junction
for deleting junctions whose paths contain wildcard characters (e.g.[
,]
, etc.). - Created
Remove-DotNetAppSetting
function for removing app settings from .NET framework machine.config files. - Created
Read-File
function for reading text files and retrying if the read fails. Good for reading files that get intermittently locked, like the Windows hosts file. - Created
Write-File
function for writing text files and retrying if the write fails. Good for writing files that get intermittently locked, like the Windows hosts file. - Made the following functions obsolete:
Get-WindowsFeature
Install-Msmq
Install-WindowsFeature
Resolve-WindowsFeatureName
Uninstall-WindowsFeature
Bug Fixes
- Fixed:
Add-GroupMember
, over PowerShell remoting, fails to add a member to groups that have non-local users/groups (fixes issue #187: Add-GroupMember fails when using PowerShell Remoting) - Fixed:
Remove-GroupMember
, over PowerShell remoting, fails to remove a member from groups that have non-local users/groups. - Fixed:
Test-PathIsJunction
returns multiple results if thePath
parameter contains wildcards and matches multiple items. - Fixed:
Install-Junction
can't install a junction whose path contains wildcard characters (fixes issue #190). - Fixed:
New-Junction
writes wrong error when creating an existing junction whose path contains wildcard characters. - Fixed:
Install-Service
doesn't update/change an existing service's account when using theCredential
parameter (fixes issue #185). - Fixed:
Uninstall-FileShare
fails if a share's physical path doesn't exist. - Fixed (hopefully):
Get-FileSharePermission
writes an error if a share's security information is corrupted (fixes issue #188). I was unable to reproduce the error, and the error was reported anonyously, so I did my best. - Fixed:
Get-PowerShellModuleInstallPath
returns multiple paths if the standard PowerShell module path is listed twice in thePSModulePath
environment variable. - Fixed: Chocolatey package fails if the standard PowerShell module path is listed twice in the
PSModulePath
environment (fixes issue #192). - Fixed:
Get-PowerShellModuleInstallPath
doesn't return the module install path if it doesn't exist. Sometimes it doesn't yet. - Fixed:
Carbon_ScheduledTask
andCarbon_IniFile
DSC resources'Get-TargetResource
functions don't return correct resource properties and causesGet-DscConfiguration
to fail (fixes issue #193). - Fixed:
Carbon_FirewallRule
DSC resource always re-installs a firewall rule ifProfile
property contains multiple values (i.e. it doesn't properly parse netsh output). - Fixed:
about_Carbon_Installation
help topic had a typo. - Fixed:
Set-HostsEntry
fails to stop when the hosts file is in use and can't be read.
This package has no dependencies.
Ground Rules:
- This discussion is only about carbon and the carbon package. If you have feedback for Chocolatey, please contact the Google Group.
- This discussion will carry over multiple versions. If you have a comment about a particular version, please note that in your comments.
- The maintainers of this Chocolatey Package will be notified about new comments that are posted to this Disqus thread, however, it is NOT a guarantee that you will get a response. If you do not hear back from the maintainers after posting a message below, please follow up by using the link on the left side of this page or follow this link to contact maintainers. If you still hear nothing back, please follow the package triage process.
- Tell us what you love about the package or carbon, or tell us what needs improvement.
- Share your experiences with the package, or extra configuration or gotchas that you've found.
- If you use a url, the comment will be flagged for moderation until you've been whitelisted. Disqus moderated comments are approved on a weekly schedule if not sooner. It could take between 1-5 days for your comment to show up.