Chocolatey Fest - Chocolatey's inaugural conference on Windows Automation (WinOps) is coming - Learn more!

84,446

Downloads

56,134

Downloads of v 2.5.0

6/18/2017

Last update

Carbon

2.5.0

Package test results are passing.

There are versions of this package awaiting moderation . See the Version History section below.

This package was approved as a trusted package on 6/30/2018.

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.

To install Carbon, run the following command from the command line or from PowerShell:

C:\> choco install carbon

To upgrade Carbon, run the following command from the command line or from PowerShell:

C:\> choco upgrade carbon

Files

Hide
  • Carbon\bin\Carbon.dll Show
    md5: 4C9BC5CEEA2BAFEF141D7C6F36DDA382 | sha1: 6E3D3078AF74E293EA74B4EEA097037E1A33E66A | sha256: 2930E2A24FDCA6E69969928211EAB52AEC52183FBE31CD963F425CA5C5740282 | sha512: 6F72061742F1FFB7F72F0F6C0CD6060EDC6142619437B0CB1EE4583276C230D3F3A9C73B3ADC5390DF0607CFB185D47DEB3A69E07CCB7120834E42555FE4F928
  • Carbon\bin\Carbon.Iis.dll Show
    md5: FBFAA9D6F302005838FA6F4E10FBDC00 | sha1: 63A7BF9E0C63BE6A7FAB13543308CFA0CDA6FA93 | sha256: 2EDDE6EB99D4FAB538528813E9148D172F6505226CA66DA4BA177553C327713D | sha512: 1DEC732638B1B2B25EEC9C6FB417A77EF6A4212E90E1C893F7B1F543787876BA95D4BD1EA9E38A4C2295F1C49343EDD835F595800690D05C51CD3BC0C06CDA91
  • Carbon\bin\Carbon.Xdt.dll Show
    md5: A4985C53CA439FC73F11960DF50F555E | sha1: 4424BBD522F2BB5D89C1F54068C1C17EC4164F5B | sha256: 0677A0468C12DACE926FE7F6C17089CB9A8549A955F11BA807E03C0DF64DCCAF | sha512: 2B6E91F636C4A1E10DC752F896768ECA83083E4ED4702BC41BBF17F37D6827EDE9EB0FB1A9EF8808410594544547BBB80A86141E8AF7B9E8EE8A83104BB329BD
  • Carbon\bin\Ionic.Zip.dll Show
    md5: C7AE289C6C0D17AA8338328D6F7133BC | sha1: 2FCDB81968F586F7D76A33C61D52BF1174EE1986 | sha256: 37C70E73717FA77DCBDBD0797CACB4AB6632C4F52F090B081968C7E1E00E25B9 | sha512: 70BC9BEEBCE4436B670278853A1A5F3B9F10C30E6CE798241D1A8C1EF6C7EAA4D57D006F0443793E2D7982EA31EE3FFD59089179529321A9CF2C79B456AB47EA
  • Carbon\bin\Microsoft.Web.XmlTransform.dll Show
    md5: 5AF30A8D40E9B69689063014A5A3A5B1 | sha1: 4FFADDF2B3C86ED345C483DA70E3ABF881187EA7 | sha256: CAE1F260E08AE53C1D671BEF1DD8F90A20D08F253CAB3984EE28D055B3C754A4 | sha512: 677D541AA895B50CED9ABEFC27F6BB8C459FE32A180A6A124BB7C0A9C9C8C89D37EF94FBCCCDBF653324888A73522C064C924D4C2F46F59DD12D19FA00546425
  • Carbon\bin\Protect-String.ps1 Show
    <#
    .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
    
    
  • Carbon\bin\Remove-DotNetAppSetting.ps1 Show
    # 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()
    }
    
  • Carbon\bin\Remove-EnvironmentVariable.ps1 Show
    # 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)]
        [string]
        $Name
    )
    
    Set-StrictMode -Version 'Latest'
    
    $Name = [Text.Encoding]::Unicode.GetString( [Convert]::FromBase64String($Name) ) 
    [Environment]::SetEnvironmentVariable( $Name, $null, [EnvironmentVariableTarget]::User )
    
  • Carbon\bin\Set-DotNetAppSetting.ps1 Show
    <#
    .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()
    
    
  • Carbon\bin\Set-DotNetConnectionString.ps1 Show
    <#
    .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()
    
    
  • Carbon\bin\Set-EnvironmentVariable.ps1 Show
    # 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)]
        [string]
        $Name,
    
        [Parameter(Mandatory=$true)]
        [string]
        $Value
    )
    
    Set-StrictMode -Version 'Latest'
    
    $Name,$Value = $Name,$Value | ForEach-Object { [Text.Encoding]::Unicode.GetString( [Convert]::FromBase64String($_) ) }
        
    [Environment]::SetEnvironmentVariable( $Name, $Value, [EnvironmentVariableTarget]::User )
    
  • Carbon\Carbon.format.ps1xml
  • Carbon\Carbon.psd1 Show
    # 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.
    #
    # Module manifest for module 'Carbon'
    #
    # Generated by: Aaron Jensen
    #
    # Generated on: 8/30/2011
    #
    
    #Requires -Version 4
    
    @{
    
        # Script module or binary module file associated with this manifest
        RootModule = 'Carbon.psm1'
    
        # Version number of this module.
        ModuleVersion = '2.5.0'
    
        # ID used to uniquely identify this module
        GUID = '075d9444-c01b-48c3-889a-0b3490716fa2'
    
        # Author of this module
        Author = 'Aaron Jensen'
    
        # Company or vendor of this module
        CompanyName = ''
    
        # Copyright statement for this module
        Copyright = 'Copyright 2011 - 2016 Aaron Jensen.'
        
        # Description of the functionality provided by this module
        Description = @'
    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.
    '@
    
        # Minimum version of the Windows PowerShell engine required by this module
        PowerShellVersion = '4.0'
    
        # Name of the Windows PowerShell host required by this module
        PowerShellHostName = ''
    
        # Minimum version of the Windows PowerShell host required by this module
        PowerShellHostVersion = ''
    
        # Minimum version of the .NET Framework required by this module
        DotNetFrameworkVersion = ''
    
        # Minimum version of the common language runtime (CLR) required by this module
        CLRVersion = ''
    
        # Processor architecture (None, X86, Amd64, IA64) required by this module
        ProcessorArchitecture = ''
    
        # Modules that must be imported into the global environment prior to importing this module
        RequiredModules = @()
    
        # Assemblies that must be loaded prior to importing this module
        RequiredAssemblies = @( 'bin\Carbon.dll' )
    
        # Script files (.ps1) that are run in the caller's environment prior to importing this module
        ScriptsToProcess = @()
    
        # Type files (.ps1xml) to be loaded when importing this module
        TypesToProcess = @(
                            'Carbon.types.ps1xml',
                            'Types\System.IO.DirectoryInfo.types.ps1xml'
                            'Types\System.IO.FileInfo.types.ps1xml'
                            'Types\System.ServiceProcess.ServiceController.types.ps1xml'
                          )
    
        # Format files (.ps1xml) to be loaded when importing this module
        FormatsToProcess = @( 'Carbon.format.ps1xml', 'Formats\Carbon.Security.HttpUrlAcl.format.ps1xml' )
    
        # Modules to import as nested modules of the module specified in ModuleToProcess
        NestedModules = @()
    
        # Functions to export from this module
        FunctionsToExport = @(
                                'Add-GroupMember',
                                'Add-IisDefaultDocument',
                                'Add-TrustedHost',
                                'Assert-AdminPrivilege',
                                'Assert-FirewallConfigurable',
                                'Assert-Service',
                                'Clear-DscLocalResourceCache',
                                'Clear-MofAuthoringMetadata',
                                'Clear-TrustedHost',
                                'Complete-Job',
                                'Compress-Item',
                                'ConvertFrom-Base64',
                                'Convert-SecureStringToString',
                                'ConvertTo-Base64',
                                'ConvertTo-ContainerInheritanceFlags',
                                'ConvertTo-InheritanceFlag',
                                'ConvertTo-PropagationFlag',
                                'ConvertTo-SecurityIdentifier',
                                'Convert-XmlFile',
                                'Copy-DscResource',
                                'Disable-AclInheritance',
                                'Disable-FirewallStatefulFtp',
                                'Disable-IEEnhancedSecurityConfiguration',
                                'Disable-IisSecurityAuthentication',
                                'Disable-NtfsCompression',
                                'Enable-AclInheritance',
                                'Enable-FirewallStatefulFtp',
                                'Enable-IEActivationPermission',
                                'Enable-IisDirectoryBrowsing',
                                'Enable-IisSecurityAuthentication',
                                'Enable-IisSsl',
                                'Enable-NtfsCompression',
                                'Expand-Item',
                                'Find-ADUser',
                                'Format-ADSearchFilterValue',
                                'Get-ADDomainController',
                                'Get-Certificate',
                                'Get-CertificateStore',
                                'Get-ComPermission',
                                'Get-ComSecurityDescriptor',
                                'Get-DscError',
                                'Get-DscWinEvent',
                                'Get-FileShare',
                                'Get-FileSharePermission',
                                'Get-FirewallRule',
                                'Get-Group',
                                'Get-HttpUrlAcl',
                                'Get-IisApplication',
                                'Get-IisAppPool',
                                'Get-IisConfigurationSection',
                                'Get-IisHttpHeader',
                                'Get-IisHttpRedirect',
                                'Get-IisMimeMap',
                                'Get-IisSecurityAuthentication',
                                'Get-IisVersion',
                                'Get-IisWebsite',
                                'Get-IPAddress',
                                'Get-Msi',
                                'Get-MsmqMessageQueue',
                                'Get-MsmqMessageQueuePath',
                                'Get-PathProvider',
                                'Get-PathToHostsFile',
                                'Get-PerformanceCounter',
                                'Get-Permission',
                                'Get-PowerShellModuleInstallPath',
                                'Get-PowershellPath',
                                'Get-Privilege',
                                'Get-ProgramInstallInfo',
                                'Get-RegistryKeyValue',
                                'Get-ScheduledTask',
                                'Get-ServiceAcl',
                                'Get-ServiceConfiguration',
                                'Get-ServicePermission',
                                'Get-ServiceSecurityDescriptor',
                                'Get-SslCertificateBinding',
                                'Get-TrustedHost',
                                'Get-User',
                                'Get-WindowsFeature',
                                'Get-WmiLocalUserAccount',
                                'Grant-ComPermission',
                                'Grant-HttpUrlPermission',
                                'Grant-MsmqMessageQueuePermission',
                                'Grant-Permission',
                                'Grant-Privilege',
                                'Grant-ServiceControlPermission',
                                'Grant-ServicePermission',
                                'Initialize-Lcm',
                                'Install-Certificate',
                                'Install-Directory',
                                'Install-FileShare',
                                'Install-Group',
                                'Install-IisApplication',
                                'Install-IisAppPool',
                                'Install-IisVirtualDirectory',
                                'Install-IisWebsite',
                                'Install-Junction',
                                'Install-Msi',
                                'Install-Msmq',
                                'Install-MsmqMessageQueue',
                                'Install-PerformanceCounter',
                                'Install-RegistryKey',
                                'Install-ScheduledTask',
                                'Install-Service',
                                'Install-User',
                                'Install-WindowsFeature',
                                'Invoke-AppCmd',
                                'Invoke-PowerShell',
                                'Join-IisVirtualPath',
                                'Lock-IisConfigurationSection',
                                'New-Credential',
                                'New-Junction',
                                'New-RsaKeyPair',
                                'New-TempDirectory',
                                'Protect-String',
                                'Read-File',
                                'Remove-DotNetAppSetting',
                                'Remove-EnvironmentVariable',
                                'Remove-GroupMember',
                                'Remove-HostsEntry',
                                'Remove-IisMimeMap',
                                'Remove-IniEntry',
                                'Remove-Junction',
                                'Remove-RegistryKeyValue',
                                'Remove-SslCertificateBinding',
                                'Reset-HostsFile',
                                'Reset-MsmqQueueManagerID',
                                'Resolve-FullPath',
                                'Resolve-Identity',
                                'Resolve-IdentityName',
                                'Resolve-NetPath',
                                'Resolve-PathCase',
                                'Resolve-RelativePath',
                                'Restart-RemoteService',
                                'Revoke-ComPermission',
                                'Revoke-HttpUrlPermission',
                                'Revoke-Permission',
                                'Revoke-Privilege',
                                'Revoke-ServicePermission',
                                'Set-DotNetAppSetting',
                                'Set-DotNetConnectionString',
                                'Set-EnvironmentVariable',
                                'Set-HostsEntry',
                                'Set-IisHttpHeader',
                                'Set-IisHttpRedirect',
                                'Set-IisMimeMap',
                                'Set-IisWebsiteID',
                                'Set-IisWebsiteSslCertificate',
                                'Set-IisWindowsAuthentication',
                                'Set-IniEntry',
                                'Set-RegistryKeyValue',
                                'Set-ServiceAcl',
                                'Set-SslCertificateBinding',
                                'Set-TrustedHost',
                                'Split-Ini',
                                'Start-DscPullConfiguration',
                                'Test-AdminPrivilege',
                                'Test-DotNet',
                                'Test-DscTargetResource',
                                'Test-FileShare',
                                'Test-FirewallStatefulFtp',
                                'Test-Group',
                                'Test-GroupMember',
                                'Test-Identity',
                                'Test-IisAppPool',
                                'Test-IisConfigurationSection',
                                'Test-IisSecurityAuthentication',
                                'Test-IisWebsite',
                                'Test-IPAddress',
                                'Test-MsmqMessageQueue',
                                'Test-NtfsCompression',
                                'Test-OSIs32Bit',
                                'Test-OSIs64Bit',
                                'Test-PathIsJunction',
                                'Test-PerformanceCounter',
                                'Test-PerformanceCounterCategory',
                                'Test-Permission',
                                'Test-PowerShellIs32Bit',
                                'Test-PowerShellIs64Bit',
                                'Test-Privilege',
                                'Test-RegistryKeyValue',
                                'Test-ScheduledTask',
                                'Test-Service',
                                'Test-SslCertificateBinding',
                                'Test-TypeDataMember',
                                'Test-UncPath',
                                'Test-User',
                                'Test-WindowsFeature',
                                'Test-ZipFile',
                                'Uninstall-Certificate',
                                'Uninstall-Directory',
                                'Uninstall-FileShare',
                                'Uninstall-Group',
                                'Uninstall-IisAppPool',
                                'Uninstall-IisWebsite',
                                'Uninstall-Junction',
                                'Uninstall-MsmqMessageQueue',
                                'Uninstall-PerformanceCounterCategory',
                                'Uninstall-ScheduledTask',
                                'Uninstall-Service',
                                'Uninstall-User',
                                'Uninstall-WindowsFeature',
                                'Unlock-IisConfigurationSection',
                                'Unprotect-String',
                                'Write-DscError',
                                'Write-File'
                            )
    
        # Cmdlets to export from this module
        CmdletsToExport = ''
    
        # Variables to export from this module
        VariablesToExport = ''
    
        # Aliases to export from this module
        AliasesToExport = '*'
    
        # List of all modules packaged with this module
        ModuleList = @()
    
        # List of all files packaged with this module
        FileList = @()
    
        # Private data to pass to the module specified in ModuleToProcess
        PrivateData = @{
    
            PSData = @{
    
                # Tags applied to this module. These help with module discovery in online galleries.
                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')
    
                # A URL to the license for this module.
                LicenseUri = 'http://www.apache.org/licenses/LICENSE-2.0'
    
                # A URL to the main website for this project.
                ProjectUri = 'http://get-carbon.org/'
    
                # ReleaseNotes of this module
                ReleaseNotes = @'
    ## Enhancements
    
     * Added `DelayedAutoStart` boolean property to objects returned by `Get-ServiceConfiguration`. This flag is `true` when a service is set to start automatically, delayed. `False` otherwise. Added extended 
     * The `Install-Service` function and the `Carbon_Service` DSC resource can now set a service's startup type to `Automatic (Delayed)`. Pass `Automatic` to the `StartupType` parameter and use the new `Delayed` switch. The `Delayed` switch is ignored unless `StartupType` is `Automatic`. Fixes [issue #216](https://bitbucket.org/splatteredbits/carbon/issues/216/community-add-automaticdelayed-in).
     * The `Uninstall-Certificate` function can now delete a certificate by just its thumbprint. The certificate will be uninstalled from *all* stores. You can pipe the thumbprint or a certificate object to `Uninstall-Certificate`.
     * Added an `EnsureRunning` switch to `Install-Service` function to ensure that any service is started after configuring. (By default, `Install-Service` leaves a service stopped if it was stopped when `Install-Service` begins.)
     * Added `IsSymbolicLink` extended type property to directory and file objects (i.e. `System.IO.DirectoryInfo` and `System.IO.FileInfo` objects).
     * Added `TargetPath` extended type property to file (i.e. `System.IO.FileInfo`) objects. If a file is a symbolic link, this property will return the file the link points to.
     * The `TargetPath` extended type property on directory (i.e. `System.IO.DirectoryInfo) objects now returns target paths when a directory is a symbolic link.
     * `Initiazlie-Lcm` can't be used on Windows Server 2016 and later to put the DSC local configuration manager into pull mode. `Initialize-Lcm` now writes an error when you try.
     
    ## Bug Fixes
    
     * `Install-Service` and the `Carbon_Service` DSC resource write errors when a service is running and its startup type is changed to `Disabled`.
     * The `Carbon_ScheduledTask` DSC resource writes incorrect information to verbose log when the current and desired credential for the scheduled task are different.
     * The `Carbon_ScheduledTask` DSC resource doesn't correctly detect when a task's identity has changed (it wasn't converting usernames to their canonical representation before comparing the existing identity with the desired identity).
     * Fixed: Importing Carbon in 32-bit PowerShell fails on a 64-bit operating system. DSC isn't available so the `Initialize-Lcm` function can't be exported. Thanks to [Anders Andersson](https://bitbucket.org/McAndersDK/) for contribuging the fix.
     * Fixed: `Install-Service` and `Carbon_Service` DSC resource fail to change the identity a service runs as if switching from a custom account to the default `NetworkService` account.
     * Fixed: `Get-PowerShellModuleInstallPath` returns nothing when run under 32-bit (x86) PowerShell on 64-bit Windows.Fixed: `Get-PowerShellModuleInstallPath` returns nothing when run under 32-bit (x86) PowerShell on 64-bit Windows.
    '@
            } # End of PSData hashtable
        
        } # End of PrivateData hashtable
    }
    
  • Carbon\Carbon.psm1 Show
    # 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 = @{ }
    
    if( [Environment]::Is64BitOperatingSystem -and -not [Environment]::Is64BitProcess ) 
    {
        $doNotImport['Initialize-Lcm.ps1'] = $true
    }
    
    $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)
  • Carbon\Carbon.types.ps1xml
  • Carbon\DscResources\Carbon_EnvironmentVariable\Carbon_EnvironmentVariable.psm1 Show
    # 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'
    
    
  • Carbon\DscResources\Carbon_EnvironmentVariable\Carbon_EnvironmentVariable.schema.mof
  • Carbon\DscResources\Carbon_FirewallRule\Carbon_FirewallRule.psm1 Show
    # 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]
                }
                if( $argName -eq 'Profile' )
                {
                    $argValue = $argValue -join ','
                }
    
                [void]$netshArgs.Add( ('{0}=' -f $argName) )
                [void]$netshArgs.Add( $argValue )
            }
        
        Write-Verbose ('{0} firewall rule ''{1}'': cmd= {2}; name= {3}; newArg: {4}; netshargs= {5}' -f $cmdDisplayName,$Name,$cmd,$Name,$newArg,($netshArgs -join ' '))
        Write-Debug -Message ('cmd= {0}; name= {1}; newArg: {2}; netshargs= {3}' -f $cmd,$Name,$newArg,($netshArgs -join ' '))
        $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)
    }
    
    
    
    
  • Carbon\DscResources\Carbon_FirewallRule\Carbon_FirewallRule.schema.mof
  • Carbon\DscResources\Carbon_Group\Carbon_Group.psm1 Show
    # 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
    
    
  • Carbon\DscResources\Carbon_Group\Carbon_Group.schema.mof
  • Carbon\DscResources\Carbon_IniFile\Carbon_IniFile.psm1 Show
    # 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'
    
    
  • Carbon\DscResources\Carbon_IniFile\Carbon_IniFile.schema.mof
  • Carbon\DscResources\Carbon_Permission\Carbon_Permission.psm1 Show
    # 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 path on which the permissions should be granted.  Can be a file system or registry path.
            $Path,
            
            [Parameter(Mandatory=$true)]
            [string]
            # The user or group getting the permissions.
            $Identity,
            
            [ValidateSet("CreateFiles","AppendData","CreateSubKey","EnumerateSubKeys","CreateLink","Delete","ChangePermissions","ExecuteFile","DeleteSubdirectoriesAndFiles","FullControl","GenericRead","GenericAll","GenericExecute","QueryValues","ReadAttributes","ReadData","ReadExtendedAttributes","GenericWrite","Notify","ReadPermissions","Read","ReadAndExecute","Modify","SetValue","ReadKey","TakeOwnership","WriteAttributes","Write","Synchronize","WriteData","WriteExtendedAttributes","WriteKey")]
            [string[]]
            # The permission: e.g. FullControl, Read, etc.  For file system items, use values from [System.Security.AccessControl.FileSystemRights](http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemrights.aspx).  For registry items, use values from [System.Security.AccessControl.RegistryRights](http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.registryrights.aspx).
            $Permission,
            
            [ValidateSet('Container','SubContainers','ContainerAndSubContainers','Leaves','ContainerAndLeaves','SubContainersAndLeaves','ContainerAndSubContainersAndLeaves','ChildContainers','ContainerAndChildContainers','ChildLeaves','ContainerAndChildLeaves','ChildContainersAndChildLeaves','ContainerAndChildContainersAndChildLeaves')]
            [string]
            # How to apply container permissions.  This controls the inheritance and propagation flags.  Default is full inheritance, e.g. `ContainersAndSubContainersAndLeaves`. This parameter is ignored if `Path` is to a leaf item.
            $ApplyTo,
            
            [ValidateSet('Present','Absent')]
            [string]
            # Should the user exist or not exist?
            $Ensure = 'Present'
        )
    
        Set-StrictMode -Version 'Latest'
    
        $resource = @{
                        Path = $Path;
                        Identity = $Identity;
                        Permission = @();
                        ApplyTo = $null;
                        Ensure = 'Absent';
                    }
    
        $perm = Get-Permission -Path $Path -Identity $Identity
        if( $perm )
        {
            [string[]]$resource.Permission = $perm | 
                                                Get-Member -Name '*Rights' -MemberType Property | 
                                                ForEach-Object { ($perm.($_.Name)).ToString() -split ',' } |
                                                ForEach-Object { $_.Trim() } | 
                                                Where-Object { $_ -ne 'Synchronize' }
    
            $resource.ApplyTo = ConvertTo-ContainerInheritanceFlags -InheritanceFlags $perm.InheritanceFlags -PropagationFlags $perm.PropagationFlags
            $resource.Ensure = 'Present'
        }
    
        return $resource
    }
    
    
    function Set-TargetResource
    {
        <#
        .SYNOPSIS
        DSC resource for managing permissions on files, directories, registry keys, or a certificate's private key.
    
        .DESCRIPTION
        The `Carbon_Permission` resource can grant or revoke permissions on a file, a directory, a registry key, or a certificate's private key.
    
        ### Granting Permission
    
        Permissions are granted when the `Ensure` property is set to `Present`.
        
        When granting permissions, you *must* supply a value for the `Permission` property. Valid values are:
    
         * CreateFiles
         * AppendData
         * CreateSubKey
         * EnumerateSubKeys
         * CreateLink
         * Delete
         * ChangePermissions
         * ExecuteFile
         * DeleteSubdirectoriesAndFiles
         * FullControl
         * GenericRead
         * GenericAll
         * GenericExecute
         * QueryValues
         * ReadAttributes
         * ReadData
         * ReadExtendedAttributes
         * GenericWrite
         * Notify
         * ReadPermissions
         * Read
         * ReadAndExecute
         * Modify
         * SetValue
         * ReadKey
         * TakeOwnership
         * WriteAttributes
         * Write
         * Synchronize
         * WriteData
         * WriteExtendedAttributes
         * WriteKey
        
        The `ApplyTo` property is only used when setting permissions on a directory or a registry key. Valid values are:
    
         * Container
         * SubContainers
         * ContainerAndSubContainers
         * Leaves
         * ContainerAndLeaves
         * SubContainersAndLeaves
         * ContainerAndSubContainersAndLeaves
         * ChildContainers
         * ContainerAndChildContainers
         * ChildLeaves
         * ContainerAndChildLeaves
         * ChildContainersAndChildLeaves
         * ContainerAndChildContainersAndChildLeaves
    
        ### Revoking Permission
            
        Permissions are revoked when the `Ensure` property is set to `Absent`. *All* a user or group's permissions are revoked. You can't revoke part of a principal's access. If you want to revoke part of a principal's access, set the `Ensure` property to `Present` and the `Permissions` property to the list of properties you want the principal to have.
    
        `Carbon_Permission` is new in Carbon 2.0.
    
        .LINK
        Get-Permission
    
        .LINK
        Grant-Permission
    
        .LINK
        Revoke-Permission
    
        .LINK
        Test-Permission
    
        .LINK
        http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemrights.aspx
        
        .LINK
        http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.registryrights.aspx
        
        .LINK
        http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.cryptokeyrights.aspx
        
        .LINK
        http://msdn.microsoft.com/en-us/magazine/cc163885.aspx#S3    
        
        .EXAMPLE
        >
        Demonstrates how to grant permissions to an item on the file system.
    
            Carbon_Permission GrantPermission
            {
                Path = 'C:\Projects\Carbon';
                Identity = 'CarbonServiceUser';
                Permission = 'ReadAndExecute';
            }
    
        This will grant `ReadAndExecute` permission to the `CarbonServiceUser` on the `C:\Projects\Carbon` directory.
    
        .EXAMPLE
        >
        Demonstrates how to grant permissions to a registry key.
    
            Carbon_Permission GrantPermission
            {
                Path = 'hklm:\SOFTWARE\Carbon';
                Identity = 'CarbonServiceUser';
                Permission = 'ReadKey';
            }
    
        This will grant `ReadKey` permission to the `CarbonServiceUser` on the `C:\Projects\Carbon` directory.
    
        .EXAMPLE
        >
        Demonstrates how to grant permissions to a certificate's private key and how to grant multiple permissions.
    
            Carbon_Permission GrantPermission
            {
                Path = 'cert:\LocalMachine\My\1234567890ABCDEF1234567890ABCDEF12345678';
                Identity = 'CarbonServiceUser';
                Permission = 'GenericRead','ReadKey';
            }
    
        This will grant `GenericRead` and `ReadKey` permissions to the `CarbonServiceUser` on the `C:\Projects\Carbon` directory.
    
        .EXAMPLE
        >
        Demonstrates how to revoke permissions.
    
            Carbon_Permission GrantPermission
            {
                Path = 'C:\Projects\Carbon';
                Identity = 'CarbonServiceUser';
                Ensure = 'Absent';
            }
    
        This will revoke all of the `CarbonServiceUser` user's permissions on the `C:\Projects\Carbon`.
    
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The path on which the permissions should be granted.  Can be a file system, registry path, or certificate path.
            $Path,
            
            [Parameter(Mandatory=$true)]
            [string]
            # The user or group getting the permissions.
            $Identity,
            
            [ValidateSet("CreateFiles","AppendData","CreateSubKey","EnumerateSubKeys","CreateLink","Delete","ChangePermissions","ExecuteFile","DeleteSubdirectoriesAndFiles","FullControl","GenericRead","GenericAll","GenericExecute","QueryValues","ReadAttributes","ReadData","ReadExtendedAttributes","GenericWrite","Notify","ReadPermissions","Read","ReadAndExecute","Modify","SetValue","ReadKey","TakeOwnership","WriteAttributes","Write","Synchronize","WriteData","WriteExtendedAttributes","WriteKey")]
            [string[]]
            # The permission: e.g. FullControl, Read, etc. Mandatory when granting permission. Valid values are `CreateFiles`, `AppendData`, `CreateSubKey`, `EnumerateSubKeys`, `CreateLink`, `Delete`, `ChangePermissions`, `ExecuteFile`, `DeleteSubdirectoriesAndFiles`, `FullControl`, `GenericRead`, `GenericAll`, `GenericExecute`, `QueryValues`, `ReadAttributes`, `ReadData`, `ReadExtendedAttributes`, `GenericWrite`, `Notify`, `ReadPermissions`, `Read`, `ReadAndExecute`, `Modify`, `SetValue`, `ReadKey`, `TakeOwnership`, `WriteAttributes`, `Write`, `Synchronize`, `WriteData`, `WriteExtendedAttributes`, `WriteKey`.
            $Permission,
            
            [ValidateSet('Container','SubContainers','ContainerAndSubContainers','Leaves','ContainerAndLeaves','SubContainersAndLeaves','ContainerAndSubContainersAndLeaves','ChildContainers','ContainerAndChildContainers','ChildLeaves','ContainerAndChildLeaves','ChildContainersAndChildLeaves','ContainerAndChildContainersAndChildLeaves')]
            [string]
            # How to apply container permissions.  This controls the inheritance and propagation flags.  Default is full inheritance, e.g. `ContainersAndSubContainersAndLeaves`. This parameter is only used when `Path` is a directory or registry key. Valid values are `Container`, `SubContainers`, `ContainerAndSubContainers`, `Leaves`, `ContainerAndLeaves`, `SubContainersAndLeaves`, `ContainerAndSubContainersAndLeaves`, `ChildContainers`, `ContainerAndChildContainers`, `ChildLeaves`, `ContainerAndChildLeaves`, `ChildContainersAndChildLeaves`, `ContainerAndChildContainersAndChildLeaves`.
            $ApplyTo,
            
            [ValidateSet('Present','Absent')]
            [string]
            # If set to `Present`, permissions are set. If `Absent`, all permissions to `$Path` removed.
            $Ensure = 'Present'
        )
    
        Set-StrictMode -Version 'Latest'
    
    
        if( $PSBoundParameters.ContainsKey('Ensure') )
        {
            $PSBoundParameters.Remove('Ensure')
        }
        
        if( $Ensure -eq 'Absent' )
        {
            Write-Verbose ('Revoking permission for ''{0}'' to ''{1}''' -f $Identity,$Path)
            Revoke-Permission -Path $Path -Identity $Identity
        }
        else
        {
            if( -not $Permission )
            {
                Write-Error ('Permission parameter is mandatory when granting permissions. If you want to revoke a user''s permission(s), set the `Ensure` property to `Absent`.')
                return
            }
    
            Write-Verbose ('Granting permission for ''{0}'' to ''{1}'': {2}' -f $Identity,$Path,($Permission -join ','))
            Grant-Permission @PSBoundParameters
        }
    }
    
    
    function Test-TargetResource
    {
        [CmdletBinding(SupportsShouldProcess=$true)]
        [OutputType([bool])]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The path on which the permissions should be granted.  Can be a file system or registry path.
            $Path,
            
            [Parameter(Mandatory=$true)]
            [string]
            # The user or group getting the permissions.
            $Identity,
            
            [ValidateSet("CreateFiles","AppendData","CreateSubKey","EnumerateSubKeys","CreateLink","Delete","ChangePermissions","ExecuteFile","DeleteSubdirectoriesAndFiles","FullControl","GenericRead","GenericAll","GenericExecute","QueryValues","ReadAttributes","ReadData","ReadExtendedAttributes","GenericWrite","Notify","ReadPermissions","Read","ReadAndExecute","Modify","SetValue","ReadKey","TakeOwnership","WriteAttributes","Write","Synchronize","WriteData","WriteExtendedAttributes","WriteKey")]
            [string[]]
            # The permission: e.g. FullControl, Read, etc.  For file system items, use values from [System.Security.AccessControl.FileSystemRights](http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemrights.aspx).  For registry items, use values from [System.Security.AccessControl.RegistryRights](http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.registryrights.aspx).
            $Permission,
            
            [ValidateSet('Container','SubContainers','ContainerAndSubContainers','Leaves','ContainerAndLeaves','SubContainersAndLeaves','ContainerAndSubContainersAndLeaves','ChildContainers','ContainerAndChildContainers','ChildLeaves','ContainerAndChildLeaves','ChildContainersAndChildLeaves','ContainerAndChildContainersAndChildLeaves')]
            [string]
            # How to apply container permissions.  This controls the inheritance and propagation flags.  Default is full inheritance, e.g. `ContainersAndSubContainersAndLeaves`. This parameter is ignored if `Path` is to a leaf item.
            $ApplyTo,
            
            [ValidateSet('Present','Absent')]
            [string]
            # Should the user exist or not exist?
            $Ensure = 'Present'
        )
    
        Set-StrictMode -Version 'Latest'
    
        $resource = Get-TargetResource -Identity $Identity -Path $Path
        $desiredRights = ($Permission | Sort-Object) -join ','
        $currentRights = ($resource.Permission | Sort-Object) -join ','
        
        if( $Ensure -eq 'Absent' )
        {
            if( $resource.Ensure -eq 'Absent' )
            {
                Write-Verbose ('Identity ''{0}'' has no permission to ''{1}''' -f $Identity,$Path)
                return $true
            }
            
            Write-Verbose ('Identity ''{0}'' has permission to ''{1}'': {2}' -f $Identity,$Path,$currentRights)
            return $false
        }
    
        if( -not $Permission )
        {
            Write-Error ('Permission parameter is mandatory when granting permissions. If you want to revoke a user''s permission(s), set the `Ensure` property to `Absent`.')
            return
        }
    
        if( -not $currentRights )
        {
            Write-Verbose ('Identity ''{0} has no permission to ''{1}''' -f $Identity,$Path,$currentRights)
            return $false
        }
    
        if( $desiredRights -ne $currentRights )
        {
            Write-Verbose ('Identity ''{0} has stale permission to ''{1}'': {2}' -f $Identity,$Path,$currentRights)
            return $false
        }
    
        if( $ApplyTo -and $ApplyTo -ne $resource.ApplyTo )
        {
            Write-Verbose ('Identity ''{0}'' has stale inheritance/propagation flags to ''{1}'': {2}' -f $Identity,$Path,$resource.ApplyTo)
            return $false
        }
    
        return $true
    }
    
  • Carbon\DscResources\Carbon_Permission\Carbon_Permission.schema.mof
  • Carbon\DscResources\Carbon_Privilege\Carbon_Privilege.psm1 Show
    # 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
    }
    
  • Carbon\DscResources\Carbon_Privilege\Carbon_Privilege.schema.mof
  • Carbon\DscResources\Carbon_ScheduledTask\Carbon_ScheduledTask.psm1 Show
    # 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 identity that should run the task. The default is `SYSTEM`.
            $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 )
            {
                $resourceUserName = $resource.TaskCredential | ForEach-Object { Resolve-IdentityName -Name $_ }
                $desiredUserName = $TaskCredential.UserName | ForEach-Object { Resolve-IdentityName -Name $_ }
                if( $resourceUserName -ne $desiredUserName )
                {
                    Write-Verbose ('[{0}] [TaskCredential] {1} != {2}' -f $Name,$resourceUserName,$desiredUserName) -Verbose
                    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 *
    
  • Carbon\DscResources\Carbon_ScheduledTask\Carbon_ScheduledTask.schema.mof
  • Carbon\DscResources\Carbon_Service\Carbon_Service.psm1 Show
    # 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,
    
            [Switch]
            $Delayed,
            
            [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;
                        Delayed = $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.Delayed = $service.DelayedAutoStart
            $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';
            }
    
        .EXAMPLE
        >
        Demonstrates how to set a service's start type `Automatic (Delayed)`. This functionality was added in Carbon 2.5.
    
            Carbon_Service InstallNoOpService
            {
                Name = 'CarbonNoOpService';
                Path = 'C:\Projects\Carbon\bin\NoOpService.bin';
                StartupType = 'Automatic';
                Delayed = $true;
                Ensure = 'Present';
            }
        #>
        [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,
    
            [Switch]
            # Used in combination with the `StartupType` parameter to set a service's startup type to `Automatic (Delayed)`.
            #
            # If `Delayed` is true true, and `StartupType` is `Automatic` sets the service's startup type to `Automatic (Delayed)`. 
            #
            # If `Delayed` is false and `StartupType` is `Automatic, sets the service's startup type to `Automatic`.
            #
            # For all other values of `StartupType`, this parameter is ignored.
            #
            # This parameter was added in Carbon 2.5.
            $Delayed,
            
            [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,
    
            [Switch]
            $Delayed,
            
            [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)
    }
    
  • Carbon\DscResources\Carbon_Service\Carbon_Service.schema.mof
  • Carbon\DscResources\Initialize-CarbonDscResource.ps1 Show
    <#
    .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
    }
    
    
  • Carbon\en-US\about_Carbon.help.txt Show
    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.
    
        To use IIS functions, IIS  must be installed/enabled, including the 
        `Web-Scripting-Tools` feature.
    
    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
  • Carbon\en-US\about_Carbon_2.0.help.txt Show
    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).
    
  • Carbon\en-US\about_Carbon_Contributing.help.txt Show
    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
        
  • Carbon\en-US\about_Carbon_Extended_Type_Data.help.txt Show
    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.
         * `[bool] IsSymbolicLink { get; }`: returns `$true` if the directory is a symbolic
           link, `$false` otherwise. Uses the Win32 API to make this determination. This 
           function was added in Carbon 2.5.0.
         * `[string] TargetPath { get; }`: if the `DirectoryInfo` is a junction or symbolic 
           link,returns the junction's/symbolic link's target path (i.e. the path it points 
           to). Retrieving the target path for symbolic links was added in Carbon 2.5.0.
        
        ## System.IO.FileInfo
         * `[uint64] FileIndex { get; }`: the file's index. This is the file's unique 
           identifier.
         * `[bool] IsSymbolicLink { get; }`: returns `$true` if the file is a symbolic link,
           `$false` otherwise. Uses the Win32 API to make this determination. This function 
           was added in Carbon 2.5.0.
         * `[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.
         * `[string] TargetPath { get; }`: if the `FileInfo` is a symbolic link, returns the 
           symbolic link's target path (i.e. the path it points to). This property was added
           in Carbon 2.5.0.
        
        ## 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
        
        
  • Carbon\en-US\about_Carbon_Installation.help.txt Show
    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 or
        PowerShell 4 with the [Package Management PowerShell Modules
        Preview](https://www.microsoft.com/en-us/download/details.aspx?id=51451)
        installed.
    
        
        To install, run:
        
            PS> Install-Module -Name 'Carbon' -AllowClobber
        
        Note: You need the `-AllowClobber` switch because Windows 10/2016 ships with
        modules that contain functions with the same name as some of Carbon's
        functions.
        
        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/
    
  • Carbon\en-US\about_Carbon_Support.help.txt Show
    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 dedicated support channel on the [PowerShell Slack 
        team](https://powershell.slack.com). The project owner/maintainer usually hangs out 
        there Monday through Friday, during Pacific-time-zone business hours. To join the 
        team, use [this form at slack.poshcode.org](http://slack.poshcode.org/) to get an 
        invitation.
    
    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://powershell.slack.com/
        http://slack.poshcode.org/
        [email protected]
        https://groups.google.com/forum/#!forum/carbonps
        https://bitbucket.org/splatteredbits/carbon/issues?status=new&status=open
    
  • Carbon\Formats\Carbon.Security.HttpUrlAcl.format.ps1xml
  • Carbon\Functions\Add-GroupMember.ps1 Show
    # 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'
    
    
  • Carbon\Functions\Add-IisDefaultDocument.ps1 Show
    # 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() 
        }
    }
    
    
  • Carbon\Functions\Add-IisServerManagerMember.ps1 Show
    # 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
        }
    }
    
    
  • Carbon\Functions\Add-TrustedHost.ps1 Show
    # 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'
    
  • Carbon\Functions\Assert-AdminPrivilege.ps1 Show
    # 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'
    
    
  • Carbon\Functions\Assert-FirewallConfigurable.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Assert-Service.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Assert-WindowsFeatureFunctionsSupported.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Clear-DscLocalResourceCache.ps1 Show
    # 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
    }
    
  • Carbon\Functions\Clear-MofAuthoringMetadata.ps1 Show
    # 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-MofAuthoringMetadata
    {
        <#
        .SYNOPSIS
        Removes authoring metadata from .mof files.
    
        .DESCRIPTION
        Everytime PowerShell generates a .mof file, it includes authoring metadata: who created the file, on what computer, and at what date/time. This means a .mof file's checksum will change everytime a new one is generated, even if the configuration in that file didn't change. This makes it hard to know when a configuration in a .mof file has truly changed, and makes its change history noisy. This function strips/removes all authoring metadata from a .mof file.
    
        When given a path to a file, all authoring metadata is removed from that file. When given the path to a directory, removes authoring metadata from all `*.mof` files in that directory.
    
        Essentially, these blocks from each .mof file:
    
            /*
            @TargetNode='********'
            @GeneratedBy=********
            @GenerationDate=08/19/2014 13:29:15
            @GenerationHost=********
            */
    
            /* ...snip... */
    
            
            instance of OMI_ConfigurationDocument
            {
             Version="1.0.0";
             Author="********;
             GenerationDate="08/19/2014 13:29:15";
             GenerationHost="********";
            };
    
        Would be changed to:
    
            /*
            @TargetNode='JSWEB01L-WHS-08'
            */
    
            /* ...snip... */
            
            instance of OMI_ConfigurationDocument
            {
             Version="1.0.0";
            };
    
    
        `Clear-MofAuthoringMetadata` is new in Carbon 2.0.
    
        .EXAMPLE
        Clear-MofAuthoringMetadata -Path 'C:\Projects\DSC\localhost.mof'
    
        Demonstrates how to clear the authoring data from a specific file.
    
        .EXAMPLE
        Clear-MofAuthoringMetadata -Path 'C:\Projects\DSC'
    
        Demonstrates how to clear the authoring data from all .mof files in a specific directory.
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The path to the file/directory whose .mof files should be operated on.
            $Path
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $tempDir = New-TempDirectory -Prefix ('Carbon+ClearMofAuthoringMetadata+') -WhatIf:$false
    
        foreach( $item in (Get-ChildItem -Path $Path -Filter '*.mof') )
        {
            Write-Verbose ('Clearing authoring metadata from ''{0}''.' -f $item.FullName)
            $tempItem = Copy-Item -Path $item.FullName -Destination $tempDir -PassThru -WhatIf:$false
            $inComment = $false
            $inAuthoringComment = $false
            $inConfigBlock = $false;
            Get-Content -Path $tempItem |
                Where-Object {
                    $line = $_
    
                    if( $line -like '/`**' )
                    {
                        if( $line -like '*`*/' )
                        {
                            return $true
                        }
                        $inComment = $true
                        return $true
                    }
    
                    if( $inComment )
                    {
                        if( $line -like '*`*/' )
                        {
                            $inComment = $false
                            $inAuthoringComment = $false
                            return $true
                        }
    
                        if( $line -like '@TargetNode=*' )
                        {
                            $inAuthoringComment = $true
                            return $true
                        }
    
                        if( $inAuthoringComment )
                        {
                            return ( $line -notmatch '^@(GeneratedBy|Generation(Host|Date))' )
                        }
    
                        return $true
                    }
    
                    if( $line -eq 'instance of OMI_ConfigurationDocument' )
                    {
                        $inConfigBlock = $true
                        return $true
                    }
    
                    if( $inConfigBlock )
                    {
                        if( $line -like '};' )
                        {
                            $inConfigBlock = $false;
                            return $true
                        }
    
                        return ($line -notmatch '(Author|(Generation(Date|Host)))=');
                    }
    
                    return $true
    
                } | 
                Set-Content -Path $item.FullName
        }
    }
    
  • Carbon\Functions\Clear-TrustedHost.ps1 Show
    # 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'
    
  • Carbon\Functions\Complete-Job.ps1 Show
    # 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'
    
  • Carbon\Functions\Compress-Item.ps1 Show
    # 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. If you're using the `WhatIf` switch, nothing is returned.
    
        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
            $fullPaths = New-Object -TypeName 'Collections.Generic.List[string]'
    
            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 { $fullPaths.Add( $_ ) }
        }
    
        end
        {
            if( -not $zipFile )
            {
                return
            }
    
            $shouldProcessCaption = ('creating compressed file ''{0}''' -f $outFile)
            $maxPathLength = $fullPaths | Select-Object -ExpandProperty 'Length' | Measure-Object -Maximum
            $maxPathLength = $maxPathLength.Maximum
            $shouldProcessFormat = 'compressing {{0,-{0}}} to {{1}}@{{2}}' -f $maxPathLength
            
            $fullPaths | ForEach-Object { 
                $zipEntryName = Split-Path -Leaf -Path $_
                $operation = $shouldProcessFormat -f $_,$OutFile,$zipEntryName
                if( $PSCmdlet.ShouldProcess($operation,$operation,$shouldProcessCaption) )
                {
                    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( $_, '.' )
                        }
                    }
                }
            }
    
            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
            {
                $operation = 'saving {0}' -f $OutFile
                if( $PSCmdlet.ShouldProcess( $operation, $operation, $shouldProcessCaption ) )
                {
                    $zipFile.Save( $OutFile )
                }
                $zipFile.Dispose()
            }
    
            $operation = 'returning {0}' -f $OutFile
            if( $PSCmdlet.ShouldProcess($operation,$operation,$shouldProcessCaption) )
            {
                Get-Item -Path $OutFile
            }
        }
    }
    
  • Carbon\Functions\Convert-SecureStringToString.ps1 Show
    # 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)
    }
    
    
  • Carbon\Functions\Convert-XmlFile.ps1 Show
    # 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
            }
        }
    }
    
    
    
  • Carbon\Functions\ConvertFrom-Base64.ps1 Show
    # 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)
            }
        }
    }
    
  • Carbon\Functions\ConvertTo-Base64.ps1 Show
    # 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)
            }
        }
    }
    
  • Carbon\Functions\ConvertTo-ContainerInheritanceFlags.ps1 Show
    # 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
            }
        }
    }
    
  • Carbon\Functions\ConvertTo-InheritanceFlag.ps1 Show
    # 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'
    
    
  • Carbon\Functions\ConvertTo-Key.ps1 Show
    # 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-Key
    {
        param(
            $From,
            $InputObject
        )
    
        Set-StrictMode -Version 'Latest'
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState    
    
        if( $InputObject -isnot [byte[]] )
        {
            if( $InputObject -is [SecureString] )
            {
                $InputObject = Convert-SecureStringToString -SecureString $InputObject
            }
            elseif( $InputObject -isnot [string] )
            {
                Write-Error -Message ('Encryption key must be a SecureString, a string, or an array of bytes not a {0}. If you are passing an array of bytes, make sure you explicitly cast it as a `byte[]`, e.g. `([byte[]])@( ... )`.' -f $InputObject.GetType().FullName)
                return
            }
    
            $Key = [Text.Encoding]::UTF8.GetBytes($InputObject)
        }
        else
        {
            $Key = $InputObject
        }
    
        if( $Key.Length -ne 128/8 -and $Key.Length -ne 192/8 -and $Key.Length -ne 256/8 )
        {
            Write-Error -Message ('Key is the wrong length. {0} is using AES, which requires a 128-bit, 192-bit, or 256-bit key (16, 24, or 32 bytes, respectively). You passed a key of {1} bits ({2} bytes).' -f $From,($Key.Length*8),$Key.Length)
            return
        }
    
        return $Key
    }
    
  • Carbon\Functions\ConvertTo-PropagationFlag.ps1 Show
    # 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'
    
    
  • Carbon\Functions\ConvertTo-ProviderAccessControlRights.ps1 Show
    # 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
            }
        }
    }
    
  • Carbon\Functions\ConvertTo-SecurityIdentifier.ps1 Show
    # 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
        }
    }
    
  • Carbon\Functions\Copy-DscResource.ps1 Show
    # 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
        }
    }
    
  • Carbon\Functions\Disable-AclInheritance.ps1 Show
    # 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-AclInheritance
    {
        <#
        .SYNOPSIS
        Protects an ACL so that changes to its parent can't be inherited to it.
        
        .DESCRIPTION
        Items in the registry or file system will inherit permissions from its parent.  The `Disable-AclInheritnace` function disables inheritance, removing all inherited permissions. You can optionally preserve the currently inherited permission as explicit permissions using the `-Preserve` switch.
        
        This function is paired with `Enable-AclInheritance`.
    
        Beginning in Carbon 2.4, this function will only disable inheritance if it is currently enabled. In previous versions, it always disabled inheritance.
    
        .LINK
        Disable-AclInheritance
        
        .LINK
        Get-Permission
    
        .LINK
        Grant-Permission
    
        .LINK
        Revoke-Permission
        
        .EXAMPLE
        Disable-AclInheritance -Path C:\Projects\Carbon
        
        Removes all inherited access rules from the `C:\Projects\Carbon` directory.  Non-inherited rules are preserved.
        
        .EXAMPLE
        Disable-AclInheritance -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)]
            [Alias('PSPath')]
            [string]
            # The file system or registry path whose access rule should stop inheriting from its parent.
            $Path,
            
            [Switch]
            # Keep the inherited access rules on this item.
            $Preserve
        )
        
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $acl = Get-Acl -Path $Path
        if( -not $acl.AreAccessRulesProtected )
        {
            Write-Verbose -Message ("[{0}] Disabling access rule inheritance." -f $Path)
            $acl.SetAccessRuleProtection( $true, $Preserve )
            $acl | Set-Acl -Path $Path
        }
    }
    
    Set-Alias -Name 'Unprotect-AclAccessRules' -Value 'Disable-AclInheritance'
    Set-Alias -Name 'Protect-Acl' -Value 'Disable-AclInheritance'
    
    
  • Carbon\Functions\Disable-FirewallStatefulFtp.ps1 Show
    # 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
        }
    }
    
    
  • Carbon\Functions\Disable-IEEnhancedSecurityConfiguration.ps1 Show
    # 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
                }
            }
    
        }
    }
    
    
  • Carbon\Functions\Disable-IisSecurityAuthentication.ps1 Show
    # 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()
        }
    }
    
    
    
  • Carbon\Functions\Disable-NtfsCompression.ps1 Show
    # 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
                }
            }
        }
    }
    
  • Carbon\Functions\Enable-AclInheritance.ps1 Show
    # 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-AclInheritance
    {
        <#
        .SYNOPSIS
        Enables ACL inheritance on an item.
        
        .DESCRIPTION
        Items in the registry or file system will usually inherit ACLs from its parent. This inheritance can be disabled, either via Carbon's `Protect-Acl` function or using .NET's securei API. The `Enable-AclInheritance` function re-enables inheritance on containers where it has been disabled. By default, any explicit permissions on the item are removed. Use the `-Preserve` switch to keep any existing, explicit permissions on the item.
        
        This function is paired with `Disable-AclInheritance`. 
    
        This function was added in Carbon 2.4.
    
        .LINK
        Disable-AclInheritance
        
        .LINK
        Get-Permission
    
        .LINK
        Grant-Permission
    
        .LINK
        Revoke-Permission
    
        .EXAMPLE
        Enable-AclInheritance -Path C:\Projects\Carbon
        
        Re-enables ACL inheritance on `C:\Projects\Carbon`. ACLs on `C:\Projects` will be inherited to and affect `C:\Projects\Carbon`. Any explicit ACLs on `C:\Projects\Carbon` are removed.
        
        .EXAMPLE
        Enable-AclInheritance -Path hklm:\Software\Carbon -Preserve
        
        Re-enables ACL inheritance on `hklm:\Software\Carbon`. ACLs on `hklm:\Software` will be inherited to and affect `hklm:\Software\Carbon`. Any explicit ACLs on `C:\Projects\Carbon` are kept.
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
            [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
            [Alias('PSPath')]
            [string]
            # The file system or registry path who should start inheriting ACLs from its parent.
            $Path,
            
            [Switch]
            # Keep the explicit access rules defined on the item.
            $Preserve
        )
        
        Set-StrictMode -Version 'Latest'
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $acl = Get-Acl -Path $Path
        if( $acl.AreAccessRulesProtected )
        {
            Write-Verbose -Message ('[{0}] Enabling access rule inheritance.' -f $Path)
            $acl.SetAccessRuleProtection($false, $Preserve)
            $acl | Set-Acl -Path $Path
    
            if( -not $Preserve )
            {
                Get-Permission -Path $Path | ForEach-Object { Revoke-Permission -Path $Path -Identity $_.IdentityReference }
            }
        }
    }
    
  • Carbon\Functions\Enable-FirewallStatefulFtp.ps1 Show
    # 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
        }
    }
    
    
  • Carbon\Functions\Enable-IEActivationPermission.ps1 Show
    # 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-IEActivationPermission
    {
        <#
        .SYNOPSIS
        Grants all users permission to start/launch Internet Explorer.
        
        .DESCRIPTION
        By default, unprivileged users can't launch/start Internet Explorer. This prevents those users from using Internet Explorer to run automated, browser-based tests.  This function modifies Windows so that all users can launch Internet Explorer.
        
        You may also need to call Disable-IEEnhancedSecurityConfiguration, so that Internet Explorer is allowed to visit all websites.
        
        .EXAMPLE
        Enable-IEActivationPermission
    
        .LINK
        Disable-IEEnhancedSecurityConfiguration
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $sddlForIe =   "O:BAG:BAD:(A;;CCDCSW;;;SY)(A;;CCDCLCSWRP;;;BA)(A;;CCDCSW;;;IU)(A;;CCDCLCSWRP;;;S-1-5-21-762517215-2652837481-3023104750-5681)"
        $binarySD = ([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD($sddlForIE)
        $ieRegPath = "hkcr:\AppID\{0002DF01-0000-0000-C000-000000000046}"
        $ieRegPath64 = "hkcr:\Wow6432Node\AppID\{0002DF01-0000-0000-C000-000000000046}"
    
        if(-not (Test-Path "HKCR:\"))
        {
            $null = New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT
        }
    
        if( $PSCmdlet.ShouldProcess( 'Internet Explorer', 'enabling launch and activation permission' ) )
        {
            Set-RegistryKeyValue -Path $ieRegPath -Name '(Default)' -String "Internet Explorer(Ver 1.0)"
            Set-RegistryKeyValue -Path $ieRegPath64 -Name '(Default)' -String "Internet Explorer(Ver 1.0)"
    
            Set-RegistryKeyValue -Path $ieRegPath -Name 'LaunchPermission' -Binary $binarySD.binarySD
            Set-RegistryKeyValue -Path $ieRegPath64 -Name 'LaunchPermission' -Binary $binarySD.binarySD
        }
    }
    
    Set-Alias -Name 'Enable-IEActivationPermissions' -Value 'Enable-IEActivationPermission'
    
  • Carbon\Functions\Enable-IisDirectoryBrowsing.ps1 Show
    # 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()
        }
    
    }
    
    
  • Carbon\Functions\Enable-IisSecurityAuthentication.ps1 Show
    # 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()
        }
    }
    
    
    
  • Carbon\Functions\Enable-IisSsl.ps1 Show
    # 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()
            }
        }
    }
    
    
  • Carbon\Functions\Enable-NtfsCompression.ps1 Show
    # 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
                }
            }
        }
    }
    
  • Carbon\Functions\Expand-Item.ps1 Show
    # 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 Expand-Item
    {
        <#
        .SYNOPSIS
        Decompresses a ZIP file to a directory using the `DotNetZip` library.
    
        .DESCRIPTION
        The contents of the ZIP file are extracted to a temporary directory, and that directory is returned as a `System.IO.DirectoryInfo` object. You are responsible for deleting that directory when you're finished.
        
        You can extract to a specific directory with the `OutDirectory` parameter. If the directory doesn't exist, it is created. If the directory exists, and is empty, the file is decompressed into that directory. If the directory isn't empty, use the `-Force` parameter to overwrite any files/directories which may be present.
    
        The directory where the files were decompressed is returned.
    
        .LINK
        https://www.nuget.org/packages/DotNetZip
    
        .LINK
        Compress-Item
    
        .LINK
        Test-ZipFile
    
        .EXAMPLE
        $unzipRoot = Expand-Item -Path 'C:\Carbon.zip' 
    
        Demonstrates how to unzip a file into a temporary directory. You are responsible for deleting that directory.
    
        .EXAMPLE
        Expand-Item -Path 'C:\Carbon.zip' -OutDirectory 'C:\Modules\Carbon'
    
        Demonstrates how to unzip a file into a specific directory.
    
        .EXAMPLE
        Expand-Item -Path 'C:\Carbon.zip' -OutDirectory 'C:\Modules\Carbon' -Force
    
        Demonstrates how to decompress to an existing, non-empty directory with the `-Force` parameter. Existing files are overwritten.
        #>
        [OutputType([IO.DirectoryInfo])]
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The path to the files/directories to compress.
            $Path,
    
            [string]
            # Path to a directory where the file should be extracted.
            $OutDirectory,
    
            [Switch]
            # Overwrite any existing files/directories in `OutDirectory`.
            $Force
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $Path = Resolve-Path -Path $Path | Select-Object -ExpandProperty 'ProviderPath'
        if( -not $Path )
        {
            return
        }
    
        if( -not (Test-ZipFile -Path $Path) )
        {
            Write-Error ('File ''{0}'' is not a ZIP file.' -f $Path)
            return
        }
    
        if( $OutDirectory )
        {
            $OutDirectory = Resolve-FullPath -Path $OutDirectory
            if( (Test-Path -Path $OutDirectory -PathType Container) )
            {
                if( -not $Force -and (Get-ChildItem -LiteralPath $OutDirectory | Measure-Object | Select-Object -ExpandProperty Count) )
                {
                    Write-Error ('Output directory ''{0}'' is not empty. Use the `-Force` switch to overwrite existing files/directories.' -f $OutDirectory)
                    return
                }
            }
        }
        else
        {
            $OutDirectory = 'Carbon+Expand-Item+{0}+{1}' -f (Split-Path -Leaf -Path $Path),([IO.Path]::GetRandomFileName())
            $OutDirectory = Join-Path -Path $env:TEMP -ChildPath $OutDirectory
            $null = New-Item -Path $OutDirectory -ItemType 'Directory'
        }
    
        $zipFile = [Ionic.Zip.ZipFile]::Read($Path)
        try
        {
            $zipFile.ExtractAll($OutDirectory, [Ionic.Zip.ExtractExistingFileAction]::OverwriteSilently)
        }
        finally
        {
            $zipFile.Dispose()
        }
    
        Get-Item -Path $OutDirectory
    }
    
  • Carbon\Functions\Find-ADUser.ps1 Show
    # 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
        }
        
    }
    
    
  • Carbon\Functions\Format-ADSearchFilterValue.ps1 Show
    # 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'
    
    
  • Carbon\Functions\Get-ADDomainController.ps1 Show
    # 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()
            }
        }
    }
    
    
  • Carbon\Functions\Get-Certificate.ps1 Show
    # 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)'."
        }
    }
    
    
  • Carbon\Functions\Get-CertificateStore.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Get-ComPermission.ps1 Show
    # 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-ComPermission
    {
        <#
        .SYNOPSIS
        Gets the COM Access or Launch and Activation permissions for the current computer.
        
        .DESCRIPTION
        COM access permissions ared used to "allow default access to application" or "set limits on applications that determine their own permissions".  Launch and Activation permissions are used "who is allowed to launch applications or activate objects" and to "set limits on applications that determine their own permissions."  Usually, these permissions are viewed and edited by opening dcomcnfg, right-clicking My Computer under Component Services > Computers, choosing Properties, going to the COM Security tab, and clicking `Edit Default...` or `Edit Limits...` buttons under the **Access Permissions** or **Launch and Activation Permissions** sections.  This function does all that, but does it much easier, and returns objects you can work with.
        
        These permissions are stored in the registry, under `HKLM\Software\Microsoft\Ole`.  The default security registry value for Access Permissions is missing/empty until custom permissions are granted.  If this is the case, this function will return objects that represent the default security, which was lovingly reverse engineered by gnomes.
        
        Returns `Carbon.Security.ComAccessRule` objects, which inherit from `[System.Security.AccessControl.AccessRule](http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.accessrule.aspx).
        
        .LINK
        Grant-ComPermission
    
        .LINK
        Revoke-ComPermission
        
        .OUTPUTS
        Carbon.Security.ComAccessRule.
         
        .EXAMPLE
        Get-ComPermission -Access -Default
        
        Gets the COM access default security permissions. Look how easy it is!
    
        .EXAMPLE
        Get-ComPermission -LaunchAndActivation -Identity 'Administrators' -Limits
        
        Gets the security limits for COM Launch and Activation permissions for the local administrators group.
        #>
        [CmdletBinding()]
        [OutputType([Carbon.Security.ComAccessRights])]
        param(
            [Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermission')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestriction')]
            [Switch]
            # If set, returns permissions for COM Access permissions.
            $Access,
            
            [Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermission')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestriction')]
            [Switch]
            # If set, returns permissions for COM Access permissions.
            $LaunchAndActivation,
            
            [Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermission')]
            [Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermission')]
            [Switch]
            # Gets default security permissions.
            $Default,
            
            [Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestriction')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestriction')]
            [Switch]
            # Gets security limit permissions.
            $Limits,
            
            [string]
            # The identity whose access rule to return.  If not set, all access rules are returned.
            $Identity        
        )
        
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $comArgs = @{ }
        if( $pscmdlet.ParameterSetName -like 'Default*' )
        {
            $comArgs.Default = $true
        }
        else
        {
            $comArgs.Limits = $true
        }
        
        if( $pscmdlet.ParameterSetName -like '*Access*' )
        {
            $comArgs.Access = $true
        }
        else
        {
            $comArgs.LaunchAndActivation = $true
        }
        
        Get-ComSecurityDescriptor @comArgs -AsComAccessRule |
            Where-Object {
                if( $Identity )
                {
                    $account = Resolve-Identity -Name $Identity
                    if( -not $account )
                    {
                        return $false
                    }
                    return ( $_.IdentityReference.Value -eq $account.FullName )
                }
                
                return $true
            }
    }
    
    Set-Alias -Name 'Get-ComPermissions' -Value 'Get-ComPermission'
    
  • Carbon\Functions\Get-ComSecurityDescriptor.ps1 Show
    # 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
        }
    }
    
    
  • Carbon\Functions\Get-DscError.ps1 Show
    # 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)
    }
    
  • Carbon\Functions\Get-DscWinEvent.ps1 Show
    # 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
        }
    }
    
  • Carbon\Functions\Get-FileShare.ps1 Show
    # 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-FileShare
    {
        <#
        .SYNOPSIS
        Gets the file/SMB shares on the local computer.
    
        .DESCRIPTION
        The `Get-FileShare` function uses WMI to get the file/SMB shares on the current/local computer. The returned objects are `Win32_Share` WMI objects.
    
        Use the `Name` paramter to get a specific file share by its name. If a share with the given name doesn't exist, an error is written and nothing is returned.
        
        The `Name` parameter supports wildcards. If you're using wildcards to find a share, and no shares are found, no error is written and nothing is returned.
    
        `Get-FileShare` was added in Carbon 2.0.
    
        .LINK
        https://msdn.microsoft.com/en-us/library/aa394435.aspx
    
        .LINK
        Get-FileSharePermission
    
        .LINK
        Install-FileShare
    
        .LINK
        Test-FileShare
    
        .LINK
        Uninstall-FileShare
    
        .EXAMPLE
        Get-FileShare
    
        Demonstrates how to get all the file shares on the local computer.
    
        .EXAMPLE
        Get-FileShare -Name 'Build'
    
        Demonstrates how to get a specific file share.
    
        .EXAMPLE
        Get-FileShare -Name 'Carbon*'
    
        Demonstrates that you can use wildcards to find all shares that match a wildcard pattern.
        #>
        [CmdletBinding()]
        param(
            [string]
            # The name of a specific share to retrieve. Wildcards accepted. If the string contains WMI sensitive characters, you'll need to escape them.
            $Name
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $filter = '(Type = 0 or Type = 2147483648)'
        $wildcardSearch = [Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name)
        if( $Name -and -not $wildcardSearch)
        {
            $filter = '{0} and Name = ''{1}''' -f $filter,$Name
        }
    
        $shares = Get-WmiObject -Class 'Win32_Share' -Filter $filter |
                        Where-Object { 
                            if( -not $wildcardSearch )
                            {
                                return $true
                            }
    
                            return $_.Name -like $Name
                        }
        
        if( $Name -and -not $shares -and -not $wildcardSearch )
        {
            Write-Error ('Share ''{0}'' not found.' -f $Name) -ErrorAction $ErrorActionPreference
        }
    
        $shares
    }
    
    
  • Carbon\Functions\Get-FileSharePermission.ps1 Show
    # 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-FileSharePermission
    {
        <#
        .SYNOPSIS
        Gets the sharing permissions on a file/SMB share.
    
        .DESCRIPTION
        The `Get-FileSharePermission` function uses WMI to get the sharing permission on a file/SMB share. It returns the permissions as a `Carbon.Security.ShareAccessRule` object, which has the following properties:
    
         * ShareRights: the rights the user/group has on the share.
         * IdentityReference: an `Security.Principal.NTAccount` for the user/group who has permission.
         * AccessControlType: the type of access control being granted: Allow or Deny.
    
        The `ShareRights` are values from the `Carbon.Security.ShareRights` enumeration. There are four values:
    
         * Read
         * Change
         * FullControl
         * Synchronize
    
        If the share doesn't exist, nothing is returned and an error is written.
    
        Use the `Identity` parameter to get a specific user/group's permissions. Wildcards are supported.
    
        `Get-FileSharePermission` was added in Carbon 2.0.
    
        .LINK
        Get-FileShare
    
        .LINK
        Install-FileShare
    
        .LINK
        Test-FileShare
    
        .LINK
        Uninstall-FileShare
    
        .EXAMPLE
        Get-FileSharePermission -Name 'Build'
    
        Demonstrates how to get all the permissions on the `Build` share.
        #>
        [CmdletBinding()]
        [OutputType([Carbon.Security.ShareAccessRule])]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The share's name.
            $Name,
    
            [string]
            # Get permissions for a specific identity. Wildcards supported.
            $Identity
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $share = Get-FileShare -Name $Name
        if( -not $share )
        {
            return
        }
    
        if( $Identity )
        {
            if( -not [System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters( $Identity ) )
            {
                $Identity = Resolve-IdentityName -Name $Identity -ErrorAction $ErrorActionPreference
                if( -not $Identity )
                {
                    return
                }
            }
        }
            
        $acl = $null  
        $lsss = Get-WmiObject -Class 'Win32_LogicalShareSecuritySetting' -Filter "name='$Name'"
        if( -not $lsss )
        {
            return
        }
    
        $result = $lsss.GetSecurityDescriptor()
        if( -not $result )
        {
            return
        }
    
        if( $result.ReturnValue )
        {
            $win32lsssErrors = @{
                                    [uint32]2 = 'Access Denied';
                                    [uint32]8 = 'Unknown Failure';
                                    [uint32]9 = 'Privilege Missing';
                                    [uint32]21 = 'Invalid Parameter';
                                }
            Write-Error ('Failed to get ''{0}'' share''s security descriptor. WMI returned error code {1} which means: {2}' -f $Name,$result.ReturnValue,$win32lsssErrors[$result.ReturnValue])
            return
        }
    
        $sd = $result.Descriptor
        if( -not $sd -or -not $sd.DACL )
        {
            return
        }
    
        foreach($ace in $SD.DACL)
        {   
            if( -not $ace -or -not $ace.Trustee )
            {
                continue
            }
    
            [Carbon.Identity]$rId = [Carbon.Identity]::FindBySid( $ace.Trustee.SIDString )
            if( $Identity -and  (-not $rId -or $rId.FullName -notlike $Identity) )
            {
                continue
            }
    
            if( $rId )
            {
                $aceId = New-Object 'Security.Principal.NTAccount' $rId.FullName
            }
            else
            {
                $aceId = New-Object 'Security.Principal.SecurityIdentifier' $ace.Trustee.SIDString
            }
    
            New-Object 'Carbon.Security.ShareAccessRule' $aceId, $ace.AccessMask, $ace.AceType
        } 
    }
    
    
  • Carbon\Functions\Get-FirewallRule.ps1 Show
    # 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. 
        
        In Carbon 2.4.0 and earlier, this data is parsed from the output of:
        
            netsh advfirewall firewall show rule name=all
    
        which only works on english-speaking computers.
    
        Beginning with Carbon 2.4.1, firewall rules are read using the Windows Firewall with Advanced Security API's `HNetCfg.FwPolicy2` object.
    
        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.
    
        This function requires administrative privileges.
    
        .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
        }
    
        $fw = New-Object -ComObject 'HNetCfg.FwPolicy2'
        $fw.Rules |
            Where-Object { 
                if( $PSCmdlet.ParameterSetName -eq 'ByLiteralName' )
                {
                    return $_.Name -eq $LiteralName
                }
    
                if( -not $Name )
                {
                    return $true
                }
    
                return $_.Name -like $Name 
            } | ForEach-Object {
        
                $rule = $_
    
                Write-Debug -Message $rule.Name
    
                $profiles = [Carbon.Firewall.RuleProfile]::Any
                if( $rule.Profiles -eq 0x7FFFFFFF )
                {
                    $profiles = [Carbon.Firewall.RuleProfile]::Domain -bor [Carbon.Firewall.RuleProfile]::Private -bor [Carbon.Firewall.RuleProfile]::Public
                }
                else
                {
                    if( ($rule.Profiles -band 1) -eq 1 )
                    {
                        $profiles = $profiles -bor [Carbon.Firewall.RuleProfile]::Domain
                    }
                    if( ($rule.Profiles -band 2) -eq 2 )
                    {
                        $profiles = $profiles -bor [Carbon.Firewall.RuleProfile]::Private
                    }
                    if( ($rule.Profiles -band 4) -eq 4 )
                    {
                        $profiles = $profiles -bor [Carbon.Firewall.RuleProfile]::Public
                    }
                }
                Write-Debug -Message ('  Profiles          {0,25} -> {1}' -f $rule.Profiles,$profiles)
                $protocol = switch( $rule.Protocol ) 
                {
                    6 { 'TCP' }
                    17 { 'UDP' }
                    1 { 'ICMPv4' }
                    58 { 'ICMPv6' }
                    256 { 'Any' }
                    default { $_ }
                }
    
                if( ($rule | Get-Member -Name 'IcmpTypesAndCodes') -and $rule.IcmpTypesAndCodes )
                {
                    $type,$code = $rule.IcmpTypesAndCodes -split ':' | ConvertTo-Any
                    if( -not $code )
                    {
                        $code = 'Any'
                    }
                    $protocol = '{0}:{1},{2}' -f $protocol,$type,$code
                    Write-Debug -Message ('  IcmpTypesAndCode  {0,25} -> {1},{2}' -f $rule.IcmpTypesAndCodes,$type,$code)
                }
                Write-Debug -Message ('  Protocol          {0,25} -> {1}' -f $rule.Protocol,$protocol)
    
                $direction = switch( $rule.Direction )
                {
                    1 { [Carbon.Firewall.RuleDirection]::In }
                    2 { [Carbon.Firewall.RuleDirection]::Out }
                }
    
                $action = switch( $rule.Action )
                {
                    0 { [Carbon.Firewall.RuleAction]::Block }
                    1 { [Carbon.Firewall.RuleAction]::Allow }
                    default { throw ('Unknown action ''{0}''.' -f $_) }
                }
    
                $interfaceType = [Carbon.Firewall.RuleInterfaceType]::Any
                $rule.InterfaceTypes -split ',' |
                    Where-Object { $_ -ne 'All' } |
                    ForEach-Object {
                        if( $_ -eq 'RemoteAccess' )
                        {
                            $_ = 'Ras'
                        }
                        $interfaceType = $interfaceType -bor [Carbon.Firewall.RuleInterfaceType]::$_
                    }
                Write-Debug -Message ('  InterfaceType     {0,25} -> {1}' -f $rule.InterfaceTypes,$interfaceType)
    
                function ConvertTo-Any
                {
                    param(
                        [Parameter(ValueFromPipeline=$true)]
                        $InputObject
                    )
    
                    process
                    {
                        if( $InputObject -eq '*' )
                        {
                            return 'Any'
                        }
    
                        $InputObject = $InputObject -split ',' |
                                            ForEach-Object { 
                                                $ipAddress,$mask = $_ -split '/'
                                                [ipaddress]$maskAddress = $null
                                                if( $mask -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$' -and [ipaddress]::TryParse($mask, [ref]$maskAddress) )
                                                {
                                                    $cidr = $maskAddress.GetAddressBytes() | 
                                                                ForEach-Object { [Convert]::ToString($_, 2) -replace '[s0]' } |
                                                                Select-Object -ExpandProperty 'Length' |
                                                                Measure-Object -Sum | 
                                                                Select-Object -ExpandProperty 'Sum'
                                                    return '{0}/{1}' -f $ipAddress,$cidr
                                                }
                                                return $_
                                            }
                        return $InputObject -join ','
                    }
                }
    
                $localAddresses = $rule.LocalAddresses | ConvertTo-Any
                Write-Debug -Message ('  LocalAddresses    {0,25} -> {1}' -f $rule.LocalAddresses,$localAddresses)
                $remoteAddresses = $rule.RemoteAddresses | ConvertTo-Any
                Write-Debug -Message ('  RemoteAddresses   {0,25} -> {1}' -f $rule.RemoteAddresses,$remoteAddresses)
                $localPorts = $rule.LocalPorts | ConvertTo-Any
                Write-Debug -Message ('  LocalPorts        {0,25} -> {1}' -f $rule.LocalPorts,$localPorts)
                $remotePorts = $rule.RemotePorts | ConvertTo-Any
                Write-Debug -Message ('  RemotePorts       {0,25} -> {1}' -f $rule.RemotePorts,$remotePorts)
    
                $edgeTraversal = switch( $rule.EdgeTraversalOptions ) 
                {
                    0 { 'No' }
                    1 { 'Yes' }
                    2 { 'Defer to application' }
                    3 { 'Defer to user' }
                }
    
                $security = [Carbon.Firewall.RuleSecurity]::NotRequired
                if( $rule | Get-Member -Name 'SecureFlags' )
                {
                    $security = switch( $rule.SecureFlags )
                    {
                        1 { [Carbon.Firewall.RuleSecurity]::AuthNoEncap }
                        2 { [Carbon.Firewall.RuleSecurity]::Authenticate }
                        3 { [Carbon.Firewall.RuleSecurity]::AuthDynEnc }
                        4 { [Carbon.Firewall.RuleSecurity]::AuthEnc }
                        default { [Carbon.Firewall.RuleSecurity]::NotRequired }
                    }
                    Write-Debug -Message ('  Security          {0,25} -> {1}' -f $rule.SecureFlags,$security)
                }
    
                $serviceName = $rule.ServiceName | ConvertTo-Any
                Write-Debug -Message ('  Service           {0,25} -> {1}' -f $rule.ServiceName,$serviceName)
    
    
                $constructorArgs = @(
                                        $rule.Name, 
                                        $rule.Enabled,
                                        $direction,
                                        $profiles,
                                        $rule.Grouping,
                                        $localAddresses,
                                        $localPorts,
                                        $remoteAddresses,
                                        $remotePorts,
                                        $protocol,
                                        $edgeTraversal,
                                        $action,
                                        $interfaceType,
                                        $security,
                                        'Local Setting', 
                                        $rule.Description,
                                        $rule.ApplicationName,
                                        $serviceName
                                    )
                New-Object -TypeName 'Carbon.Firewall.Rule' -ArgumentList $constructorArgs
            } 
    }
    
    Set-Alias -Name 'Get-FirewallRules' -Value 'Get-FirewallRule'
    
  • Carbon\Functions\Get-Group.ps1 Show
    # 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()
            }
        }
    }
    
    
  • Carbon\Functions\Get-HttpUrlAcl.ps1 Show
    # 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
            }
        }
    }
  • Carbon\Functions\Get-IdentityPrincipalContext.ps1 Show
    # 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)
    }
    
  • Carbon\Functions\Get-IisApplication.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Get-IisAppPool.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Get-IisConfigurationSection.ps1 Show
    # 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
        }
    }
    
    
  • Carbon\Functions\Get-IisHttpHeader.ps1 Show
    # 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'] }
    }
    
    
  • Carbon\Functions\Get-IisHttpRedirect.ps1 Show
    # 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])
    }
    
    
  • Carbon\Functions\Get-IisMimeMap.ps1 Show
    # 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'])
            }
    }
    
    
  • Carbon\Functions\Get-IisSecurityAuthentication.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Get-IisVersion.ps1 Show
    # 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()
    }
    
    
  • Carbon\Functions\Get-IisWebsite.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Get-IPAddress.ps1 Show
    # 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
            }
    }
    
  • Carbon\Functions\Get-Msi.ps1 Show
    # 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 
        {
        }
    }
    
  • Carbon\Functions\Get-MsmqMessageQueue.ps1 Show
    # 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-MsmqMessageQueue
    {
        <#
        .SYNOPSIS
        Gets the MSMQ message queue by the given name
    
        .DESCRIPTION 
        Returns a [MessageQueue](http://msdn.microsoft.com/en-us/library/system.messaging.messagequeue.aspx) object for the Message Queue with name `Name`.  If one doesn't exist, returns `$null`.
    
        Because MSMQ handles private queues differently than public queues, you must explicitly tell `Get-MsmqMessageQueue` the queue you want to get is private by using the `Private` switch.
    
        .OUTPUTS
        System.Messaging.MessageQueue.
    
        .EXAMPLE
        Get-MsmqMessageQueue -Name LunchQueue
    
        Returns the [MessageQueue](http://msdn.microsoft.com/en-us/library/system.messaging.messagequeue.aspx) object for the queue named LunchQueue.  It's probably pretty full!
    
        .EXAMPLE
        Get-MsmqMessageQueue -Name TeacherLunchQueue -Private
    
        Returns the [MessageQueue](http://msdn.microsoft.com/en-us/library/system.messaging.messagequeue.aspx) object for the teacher's private LunchQueue.  They must be medical professors.
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The name of the queue to get.
            $Name,
            
            [Switch]
            # Is the queue private?
            $Private
        )
       
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $privateArg = @{ Private = $Private }
        
        if( Test-MsmqMessageQueue -Name $Name @privateArg )
        {
            $path = Get-MsmqMessageQueuePath -Name $Name @privateArg 
            New-Object -TypeName Messaging.MessageQueue -ArgumentList ($path)
        }
        else
        {
            return $null
        }
    }
    
    
  • Carbon\Functions\Get-MsmqMessageQueuePath.ps1 Show
    # 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-MsmqMessageQueuePath
    {
        <#
        .SYNOPSIS
        Gets the path to an MSMQ message queue.
    
        .DESCRIPTION
        The MSMQ APIs expect paths when identifying a queue.  This function converts a queue name into its path so that logic isn't spread across all your scripts.  
    
        Private queue paths are constructed differently.  If you need to get the path to a private MSMQ, use the `Private` switch.
    
        .OUTPUTS
        System.String.
    
        .EXAMPLE
        Get-MsmqMessageQueuePath -Name MovieQueue
    
        Returns the path to the `MovieQueue` queue.
    
        .EXAMPLE
        Get-MsmqMessageQueuePath -Name MovieQueue -Private
    
        Returns the path to the private `MovieQueue`.  Must be for the critics.  Early access for the win!
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The queue's name.  
            $Name,
            
            [Switch]
            # Is the queue private?
            $Private
        )
        
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $path = ".\$Name"
        if( $Private )
        {
            $path = ".\private`$\$Name"
        }
        return $path
    }
    
    
  • Carbon\Functions\Get-PathProvider.ps1 Show
    # 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
            }
        }
    
        $pathQualifier = $pathQualifier.Trim(':')
        $drive = Get-PSDrive -Name $pathQualifier -ErrorAction Ignore
        if( -not $drive )
        {
            $drive = Get-PSDrive -PSProvider $pathQualifier -ErrorAction Ignore
        }
    
        if( -not $drive )
        {
            Write-Error -Message ('Unable to determine the provider for path {0}.' -f $Path)
            return
        }
    
        $drive  |
            Select-Object -First 1 |
            Select-Object -ExpandProperty 'Provider'
    
    }
    
  • Carbon\Functions\Get-PathToHostsFile.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Get-PerformanceCounter.ps1 Show
    # 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'
    
    
  • Carbon\Functions\Get-Permission.ps1 Show
    # 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-Permission
    {
        <#
        .SYNOPSIS
        Gets the permissions (access control rules) for a file, directory, registry key, or certificate's private key/key container.
        
        .DESCRIPTION
        Permissions for a specific identity can also be returned.  Access control entries are for a path's discretionary access control list.
        
        To return inherited permissions, use the `Inherited` switch.  Otherwise, only non-inherited (i.e. explicit) permissions are returned.
    
        Certificate permissions are only returned if a certificate has a private key/key container. If a certificate doesn't have a private key, `$null` is returned. 
        
        .OUTPUTS
        System.Security.AccessControl.AccessRule.
        
        .LINK
        Carbon_Permission
    
        .LINK
        Disable-AclInheritance
    
        .LINK
        Enable-AclInheritance
    
        .LINK
        Get-Permission
    
        .LINK
        Grant-Permission
    
        .LINK
        Revoke-Permission
    
        .LINK
        Test-Permission
    
        .EXAMPLE
        Get-Permission -Path 'C:\Windows'
        
        Returns `System.Security.AccessControl.FileSystemAccessRule` objects for all the non-inherited rules on `C:\windows`.
        
        .EXAMPLE
        Get-Permission -Path 'hklm:\Software' -Inherited
        
        Returns `System.Security.AccessControl.RegistryAccessRule` objects for all the inherited and non-inherited rules on `hklm:\software`.
        
        .EXAMPLE
        Get-Permission -Path 'C:\Windows' -Idenity Administrators
        
        Returns `System.Security.AccessControl.FileSystemAccessRule` objects for all the `Administrators'` rules on `C:\windows`.
    
        .EXAMPLE
        Get-Permission -Path 'Cert:\LocalMachine\1234567890ABCDEF1234567890ABCDEF12345678'
    
        Returns `System.Security.AccessControl.CryptoKeyAccesRule` objects for certificate's `Cert:\LocalMachine\1234567890ABCDEF1234567890ABCDEF12345678` private key/key container. If it doesn't have a private key, `$null` is returned.
        #>
        [CmdletBinding()]
        [OutputType([System.Security.AccessControl.AccessRule])]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The path whose permissions (i.e. access control rules) to return. File system, registry, or certificate paths supported. Wildcards supported.
            $Path,
            
            [string]
            # The identity whose permissiosn (i.e. access control rules) to return.
            $Identity,
            
            [Switch]
            # Return inherited permissions in addition to explicit permissions.
            $Inherited
        )
       
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $account = $null
        if( $Identity )
        {
            $account = Test-Identity -Name $Identity -PassThru
            if( $account )
            {
                $Identity = $account.FullName
            }
        }
    
        if( -not (Test-Path -Path $Path) )
        {
            Write-Error ('Path ''{0}'' not found.' -f $Path)
            return
        }
        
        Invoke-Command -ScriptBlock {
            Get-Item -Path $Path -Force |
                ForEach-Object { 
                    if( $_.PSProvider.Name -eq 'Certificate' )
                    {
                        if( $_.HasPrivateKey -and $_.PrivateKey )
                        {
                            $_.PrivateKey.CspKeyContainerInfo.CryptoKeySecurity
                        }
                    }
                    else
                    {
                        $_.GetAccessControl([Security.AccessControl.AccessControlSections]::Access)
                    }
                }
            } |
            Select-Object -ExpandProperty Access |
            Where-Object { 
                if( $Inherited )
                {
                    return $true 
                }
                return (-not $_.IsInherited)
            } |
            Where-Object {
                if( $Identity )
                {
                    return ($_.IdentityReference.Value -eq $Identity)
                }
                
                return $true
            }    
    }
    
    Set-Alias -Name 'Get-Permissions' -Value 'Get-Permission'
    
    
  • Carbon\Functions\Get-PowerShellModuleInstallPath.ps1 Show
    # 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'
        if( (Test-Path -Path 'Env:\ProgramW6432') )
        {
            $programFileModulePath = Join-Path -Path $env:ProgramW6432 -ChildPath 'WindowsPowerShell\Modules'
        }
    
        $installRoot = $modulePaths | 
                            Where-Object { $_.TrimEnd('\') -eq $programFileModulePath } |
                            Select-Object -First 1
        if( $installRoot )
        {
            return $programFileModulePath
        }
    
        $psHomeModulePath = Join-Path -Path $env:SystemRoot -ChildPath 'system32\WindowsPowerShell\v1.0\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)
    }
    
  • Carbon\Functions\Get-PowershellPath.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Get-Privilege.ps1 Show
    # 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'
    
    
  • Carbon\Functions\Get-ProgramInstallInfo.ps1 Show
    # 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' $_ }
    }
    
  • Carbon\Functions\Get-RegistryKeyValue.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Get-ScheduledTask.ps1 Show
    # 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 -match 'The\ system\ cannot\ find\ the\ (file|path)\ 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
            }
        }
    
    }
    
  • Carbon\Functions\Get-ServiceAcl.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Get-ServiceConfiguration.ps1 Show
    # 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 all the other service configuration as a `Carbon.Service.ServiceInfo` object, which has the following properties:
        
        * `DelayedAutoStart`: A boolean value indicating if the service starts automically delayed. This property was added in Carbon 2.5.
        * `Description`: The service's description.
        * `ErrorControl`: A `Carbon.Service.ErrorControl` value that indicates the severity of the error when the service fails to start.
        * `FailureProgram`: The program to run when the service fails.
        * `FirstFailure`: A `Carbon.Service.FailureAction` value indicating what will happen after the service's first failure.
        * `LoadOrderGroup`: The name of the load order group this service loads in.
        * `Name`: The name of the service.
        * `Path`: The path to the service executable (with arguments).
        * `RebootDelay`: The number of milliseconds after boot to wait before the service starts.
        * `RebootDelayMinutes`: `RebootDelay` expressed in minutes.
        * `ResetPeriod`: How often, in seconds, to reset the service's failure count to 0.
        * `ResetPeriodDays`: `ResetPeriod` expressed in number of days.
        * `RestartDelay`: The number of milliseconds to wait before restarting the service after it fails.
        * `RestartDelayMinutes`: `RestartDelay` expressed in minutes.
        * `RunCommandDelay`: The number of milliseconds to wait after a service fails before running the failure program.
        * `RunCommandDelayMinutes`: `RunCommandDelay` as expressed/converted in minutes.
        * `SecondFailure`: A `Carbon.Service.FailureAction` value indicating what will happen after the service's second failure.
        * `StartType`: A `Carbon.Service.StartType` value indicating how and when the service should be started.
        * `TagID`: The service's tag ID. This is the order the service will start in its load group.
        * `ThirdFailure`: A `Carbon.Service.FailureAction` value indicating what will happen after the service's third failure.
        * `UserName`: The name of the identity the service runs as.
    
        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
        }
    }
    
  • Carbon\Functions\Get-ServicePermission.ps1 Show
    # 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-ServicePermission
    {
        <#
        .SYNOPSIS
        Gets the permissions for a service.
        
        .DESCRIPTION
        Uses the Win32 advapi32 API to query the permissions for a service.  Returns `Carbon.ServiceAccessRule` objects for each.  The two relavant properties on this object are
        
         * IdentityReference - The identity of the permission.
         * ServiceAccessRights - The permissions the user has.
         
        .OUTPUTS
        Carbon.Security.ServiceAccessRule.
        
        .LINK
        Grant-ServicePermissions
        
        .LINK
        Revoke-ServicePermissions
        
        .EXAMPLE
        Get-ServicePermission -Name 'Hyperdrive'
        
        Gets the access rules for the `Hyperdrive` service.
        
        .EXAMPLE
        Get-ServicePermission -Name 'Hyperdrive' -Identity FALCON\HSolo
        
        Gets just Han's permissions to control the `Hyperdrive` service.
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The name of the service whose permissions to return.
            $Name,
            
            [string]
            # The specific identity whose permissions to get.
            $Identity
        )
        
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $dacl = Get-ServiceAcl -Name $Name
        
        $account = $null
        if( $Identity )
        {
            $account = Resolve-Identity -Name $Identity
            if( -not $account )
            {
                return
            }
        }
    
        $dacl |
            ForEach-Object {
                $ace = $_
                
                $aceSid = $ace.SecurityIdentifier;
                if( $aceSid.IsValidTargetType([Security.Principal.NTAccount]) )
                {
                    try
                    {
                        $aceSid = $aceSid.Translate([Security.Principal.NTAccount])
                    }
                    catch [Security.Principal.IdentityNotMappedException]
                    {
                        # user doesn't exist anymore.  So sad.
                    }
                }
    
                if ($ace.AceType -eq [Security.AccessControl.AceType]::AccessAllowed)
                {
                    $ruleType = [Security.AccessControl.AccessControlType]::Allow
                }
                elseif ($ace.AceType -eq [Security.AccessControl.AceType]::AccessDenied)
                {
                    $ruleType = [Security.AccessControl.AccessControlType]::Deny
                }
                else
                {
                    Write-Error ("Unsupported aceType {0}." -f $ace.AceType)
                    return
                }
                New-Object Carbon.Security.ServiceAccessRule $aceSid,$ace.AccessMask,$ruleType            
            } |
            Where-Object { 
                if( $account )
                {
                    return ($_.IdentityReference.Value -eq $account.FullName)
                }
                return $_
            }
    }
    
    Set-Alias -Name 'Get-ServicePermissions' -Value 'Get-ServicePermission'
    
    
  • Carbon\Functions\Get-ServiceSecurityDescriptor.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Get-SslCertificateBinding.ps1 Show
    # 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
        
        [Carbon.Certificates.SslCertificateBinding]::GetSslCertificateBindings() |
            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'
    
  • Carbon\Functions\Get-TrustedHost.ps1 Show
    # 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'
    
  • Carbon\Functions\Get-User.ps1 Show
    # 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()
            }
        }
    }
    
    
  • Carbon\Functions\Get-WindowsFeature.ps1 Show
    # 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
            }        
        }
    }
  • Carbon\Functions\Get-WmiLocalUserAccount.ps1 Show
    # 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'"
    }
    
    
  • Carbon\Functions\Grant-ComPermission.ps1 Show
    # 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-ComPermission
    {
        <#
        .SYNOPSIS
        Grants COM access permissions.
        
        .DESCRIPTION
        Calling this function is equivalent to opening Component Services (dcomcnfg), right-clicking `My Computer` under Component Services > Computers, choosing `Properties`, going to the `COM Security` tab, and modifying the permission after clicking the `Edit Limits...` or `Edit Default...` buttons under the `Access Permissions` section.
        
        You must set at least one of the `LocalAccess` or `RemoteAccess` switches.
        
        .OUTPUTS
        Carbon.Security.ComAccessRule.
    
        .LINK
        Get-ComPermission
    
        .LINK
        Revoke-ComPermission
        
        .EXAMPLE
        Grant-ComPermission -Access -Identity 'Users' -Allow -Default -Local
        
        Updates access permission default security to allow the local `Users` group local access permissions.
    
        .EXAMPLE
        Grant-ComPermission -LaunchAndActivation -Identity 'Users' -Limits -Deny -Local -Remote
        
        Updates access permission security limits to deny the local `Users` group local and remote access permissions.
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [string]        
            $Identity,
            
            [Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermissionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestrictionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermissionDeny')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestrictionDeny')]
            [Switch]
            # Grants Access Permissions.
            $Access,
            
            [Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermissionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestrictionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermissionDeny')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestrictionDeny')]
            [Switch]
            # Grants Launch and Activation Permissions.
            $LaunchAndActivation,
            
            [Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermissionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermissionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermissionDeny')]
            [Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermissionDeny')]
            [Switch]
            # Grants default security permissions.
            $Default,
            
            [Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestrictionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestrictionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestrictionDeny')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestrictionDeny')]
            [Switch]
            # Grants security limits permissions.
            $Limits,
            
            [Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermissionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestrictionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermissionAllow')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestrictionAllow')]
            [Switch]
            # If set, allows the given permissions.
            $Allow,
            
            [Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermissionDeny')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestrictionDeny')]
            [Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermissionDeny')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestrictionDeny')]
            [Switch]
            # If set, denies the given permissions.
            $Deny,
                    
            [Parameter(ParameterSetName='DefaultAccessPermissionAllow')]
            [Parameter(ParameterSetName='MachineAccessRestrictionAllow')]
            [Parameter(ParameterSetName='DefaultAccessPermissionDeny')]
            [Parameter(ParameterSetName='MachineAccessRestrictionDeny')]
            [Switch]
            # If set, grants local access permissions.  Only valid if `Access` switch is set.
            $Local,
            
            [Parameter(ParameterSetName='DefaultAccessPermissionAllow')]
            [Parameter(ParameterSetName='MachineAccessRestrictionAllow')]
            [Parameter(ParameterSetName='DefaultAccessPermissionDeny')]
            [Parameter(ParameterSetName='MachineAccessRestrictionDeny')]
            [Switch]
            # If set, grants remote access permissions.  Only valid if `Access` switch is set.
            $Remote,
    
            [Parameter(ParameterSetName='DefaultLaunchPermissionAllow')]
            [Parameter(ParameterSetName='MachineLaunchRestrictionAllow')]
            [Parameter(ParameterSetName='DefaultLaunchPermissionDeny')]
            [Parameter(ParameterSetName='MachineLaunchRestrictionDeny')]
            [Switch]
            # If set, grants local launch permissions.  Only valid if `LaunchAndActivation` switch is set.
            $LocalLaunch,
            
            [Parameter(ParameterSetName='DefaultLaunchPermissionAllow')]
            [Parameter(ParameterSetName='MachineLaunchRestrictionAllow')]
            [Parameter(ParameterSetName='DefaultLaunchPermissionDeny')]
            [Parameter(ParameterSetName='MachineLaunchRestrictionDeny')]
            [Switch]
            # If set, grants remote launch permissions.  Only valid if `LaunchAndActivation` switch is set.
            $RemoteLaunch,
    
            [Parameter(ParameterSetName='DefaultLaunchPermissionAllow')]
            [Parameter(ParameterSetName='MachineLaunchRestrictionAllow')]
            [Parameter(ParameterSetName='DefaultLaunchPermissionDeny')]
            [Parameter(ParameterSetName='MachineLaunchRestrictionDeny')]
            [Switch]
            # If set, grants local activation permissions.  Only valid if `LaunchAndActivation` switch is set.
            $LocalActivation,
            
            [Parameter(ParameterSetName='DefaultLaunchPermissionAllow')]
            [Parameter(ParameterSetName='MachineLaunchRestrictionAllow')]
            [Parameter(ParameterSetName='DefaultLaunchPermissionDeny')]
            [Parameter(ParameterSetName='MachineLaunchRestrictionDeny')]
            [Switch]
            # If set, grants remote activation permissions.  Only valid if `LaunchAndActivation` switch is set.
            $RemoteActivation,
    
            [Switch]
            # Return a `Carbon.Security.ComAccessRights` object for the permissions granted.
            $PassThru
        )
        
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
        
        $account = Resolve-Identity -Name $Identity -ErrorAction:$ErrorActionPreference
        if( -not $account )
        {
            return
        }
    
        $comArgs = @{ }
        if( $pscmdlet.ParameterSetName -like 'Default*' )
        {
            $typeDesc = 'default security permissions'
            $comArgs.Default = $true
        }
        else
        {
            $typeDesc = 'security limits'
            $comArgs.Limits = $true
        }
        
        if( $pscmdlet.ParameterSetName -like '*Access*' )
        {
            $permissionsDesc = 'Access'
            $comArgs.Access = $true
        }
        else
        {
            $permissionsDesc = 'Launch and Activation'
            $comArgs.LaunchAndActivation = $true
        }
        
        $currentSD = Get-ComSecurityDescriptor @comArgs -ErrorAction:$ErrorActionPreference
    
        $newSd = ([wmiclass]'win32_securitydescriptor').CreateInstance()
        $newSd.ControlFlags = $currentSD.ControlFlags
        $newSd.Group = $currentSD.Group
        $newSd.Owner = $currentSD.Owner
    
        $trustee = ([wmiclass]'win32_trustee').CreateInstance()
        $trustee.SIDString = $account.Sid.Value
    
        $ace = ([wmiclass]'win32_ace').CreateInstance()
        $accessMask = [Carbon.Security.ComAccessRights]::Execute
        if( $Local -or $LocalLaunch )
        {
            $accessMask = $accessMask -bor [Carbon.Security.ComAccessRights]::ExecuteLocal
        }
        if( $Remote -or $RemoteLaunch )
        {
            $accessMask = $accessMask -bor [Carbon.Security.ComAccessRights]::ExecuteRemote
        }
        if( $LocalActivation )
        {
            $accessMask = $accessMask -bor [Carbon.Security.ComAccessRights]::ActivateLocal
        }
        if( $RemoteActivation )
        {
            $accessMask = $accessMask -bor [Carbon.Security.ComAccessRights]::ActivateRemote
        }
        
        Write-Verbose ("Granting {0} {1} COM {2} {3}." -f $Identity,([Carbon.Security.ComAccessRights]$accessMask),$permissionsDesc,$typeDesc)
    
        $ace.AccessMask = $accessMask
        $ace.Trustee = $trustee
    
        # Remove DACL for this user, if it exists, so we can replace it.
        $newDacl = $currentSD.DACL | 
                        Where-Object { $_.Trustee.SIDString -ne $trustee.SIDString } | 
                        ForEach-Object { $_.PsObject.BaseObject }
        $newDacl += $ace.PsObject.BaseObject
        $newSd.DACL = $newDacl
    
        $converter = New-Object Management.ManagementClass 'Win32_SecurityDescriptorHelper'
        $sdBytes = $converter.Win32SDToBinarySD( $newSd )
    
        $regValueName = $pscmdlet.ParameterSetName -replace '(Allow|Deny)$',''
        Set-RegistryKeyValue -Path $ComRegKeyPath -Name $regValueName -Binary $sdBytes.BinarySD -Quiet -ErrorAction:$ErrorActionPreference
        
        if( $PassThru )
        {
            Get-ComPermission -Identity $Identity @comArgs -ErrorAction:$ErrorActionPreference
        }
    }
    
    Set-Alias -Name 'Grant-ComPermissions' -Value 'Grant-ComPermission'
    
  • Carbon\Functions\Grant-HttpUrlPermission.ps1 Show
    # 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-HttpUrlPermission
    {
        <#
        .SYNOPSIS
        Grant a principal permission to bind to an HTTP URL.
    
        .DESCRIPTION
        The `Grant-HttpUrlAclPermission` functions uses the HTTP Server API to grant a user permission to bind to an HTTP URL.
    
        [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. A user can have three permissions: 
        
         * `Listen`, which allows the user to bind to the `$Url` url
         * `Delegate`, which allows the user to "reserve (delegate) a subtree of this URL for another user" (whatever that means)
    
        If the user already has the desired permissions, nothing happens. If the user has any permissions not specified by the `Permission` parameter, they are removed (i.e. if the user currently has delegate permission, but you don't pass that permission in, it will be removed).
    
        This command replaces the `netsh http (add|delete) urlacl` command.
    
        `Grant-HttpUrlAclPermission` was introduced in Carbon 2.1.0.
    
        .LINK
        https://msdn.microsoft.com/en-us/library/aa364653.aspx
    
        .LINK
        Get-HttpUrlAcl
    
        .LINK
        Revoke-HttpUrlPermission
    
        .EXAMPLE
        Grant-HttpUrlAclPermission -Url 'http://+:4833' -Principal 'FALCON\HSolo' -Permission [Carbon.Security.HttpUrlAccessRights]::Listen
    
        Demonstrates how to grant a user permission to listen to (i.e. "bind" or "register") an HTTP URL. In this case user `FALCON\HSolo` can listen to `http://+:4833`.
    
        .EXAMPLE
        Grant-HttpUrlAclPermission -Url 'http://+:4833' -Principal 'FALCON\HSolo' -Permission [Carbon.Security.HttpUrlAccessRights]::Delegate
    
        Demonstrates how to grant a user permission to delegate an HTTP URL, but not the ability to bind to that URL. In this case user `FALCON\HSolo` can delegate `http://+:4833`, but can't bind to it.
    
        .EXAMPLE
        Grant-HttpUrlAclPermission -Url 'http://+:4833' -Principal 'FALCON\HSolo' -Permission [Carbon.Security.HttpUrlAccessRights]::ListenAndDelegate
    
        Demonstrates how to grant a user permission to listen (i.e "bind" or "register") to *and* delegate an HTTP URL. In this case user `FALCON\HSolo` can listen to and delegate `http://+:4833`.
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The URL.
            $Url,
    
            [Parameter(Mandatory=$true)]
            [Alias('Identity')]
            [string]
            # The user receiving the permission.
            $Principal,
    
            [Parameter(Mandatory=$true)]
            [Carbon.Security.HttpUrlAccessRights]
            # The permission(s) to grant the user. There are two permissions:
            #
            #  * `Listen`, which allows the user to bind to the `$Url` url
            #  * `Delegate`, which allows the user to "reserve (delegate) a subtree of this URL for another user" (whatever that means)
            #  * `ListenAndDelegate`, which grants both `Listen` and `Delegate` permissions
            $Permission
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        if( -not $Url.EndsWith("/") )
        {
            $Url = '{0}/' -f $Url
        }
    
        $acl = Get-HttpUrlAcl -LiteralUrl $Url -ErrorAction Ignore
        if( -not $acl )
        {
            $acl = New-Object 'Carbon.Security.HttpUrlSecurity' $Url
        }
    
        $id = Resolve-Identity -Name $Principal
        if( -not $id )
        {
            return
        }
    
        $currentRule = $acl.Access | Where-Object { $_.IdentityReference -eq $id.FullName }
        $currentRights = ''
        if( $currentRule )
        {
            if( $currentRule.HttpUrlAccessRights -eq $Permission )
            {
                return
            }
            $currentRights = $currentRule.HttpUrlAccessRights
        }
    
        Write-Verbose -Message ('[{0}]  [{1}]  {2} -> {3}' -f $Url,$id.FullName,$currentRights,$Permission)
        $rule = New-Object 'Carbon.Security.HttpUrlAccessRule' $id.Sid,$Permission
        $modifiedRule = $null
        $acl.ModifyAccessRule( ([Security.AccessControl.AccessControlModification]::RemoveAll), $rule, [ref]$modifiedRule )
        $acl.SetAccessRule( $rule )
    }
  • Carbon\Functions\Grant-MsmqMessageQueuePermission.ps1 Show
    # 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-MsmqMessageQueuePermission
    {
        <#
        .SYNOPSIS
        Grants a user permissions on an MSMQ message queue.
    
        .DESCRIPTION
        If you want users to be able to access your queue, you need to grant them access.  This function will do that.
    
        The rights you can assign are specified using values from the [MessageQueueAccessRights enumeration](http://msdn.microsoft.com/en-us/library/system.messaging.messagequeueaccessrights.aspx).  
    
        If your queue is private, make sure you set the `Private` switch.
    
        .LINK
        http://msdn.microsoft.com/en-us/library/system.messaging.messagequeueaccessrights.aspx
    
        .EXAMPLE
        Grant-MsmqMessageQueuePermission -Name MovieQueue -Username REGAL\Employees -AccessRights FullControl
    
        Grants Regal Cinema employees full control over the MovieQueue.
    
        .EXAMPLE
        Grant-MsmqMessageQueuePermission -Name MovieQueue -Private -Username REGAL\Critics -AccessRights WriteMessage    
    
        Grants all of Regal's approved movie critics permission to write to the private critic's `MovieQueue`.  Lucky!
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The queue name.
            $Name,
            
            [Switch]
            # Is the queue private?
            $Private,
            
            [Parameter(Mandatory=$true)]
            [string]
            # The user to grant permissions to.
            $Username,
            
            [Parameter(Mandatory=$true)]
            [Messaging.MessageQueueAccessRights[]]
            # The rights to grant the user.
            $AccessRights
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
        
        $queueArgs = @{ Name = $Name ; Private = $Private }
        $queue = Get-MsmqMessageQueue @queueArgs
        if( -not $queue )
        {
            Write-Error "MSMQ queue '$Name' not found."
            return
        }
        
        if( $PSCmdlet.ShouldProcess( ('MSMQ queue ''{0}''' -f $Name), ("granting '{0}' rights to '{1}'" -f $AccessRights,$Username) ) )
        {
            $queue.SetPermissions( $Username, $AccessRights )
        }
    }
    
    Set-Alias -Name 'Grant-MsmqMessageQueuePermissions' -Value 'Grant-MsmqMessageQueuePermission'
    
    
  • Carbon\Functions\Grant-Permission.ps1 Show
    # 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-Permission
    {
        <#
        .SYNOPSIS
        Grants permission on a file, directory, registry key, or certificate's private key/key container.
    
        .DESCRIPTION
        The `Grant-Permission` functions grants permissions to files, directories, registry keys, and certificate private key/key containers. It detects what you are setting permissions on by inspecting the path of the item. If the path is relative, it uses the current location to determine if file system, registry, or private keys permissions should be set.
        
        The `Permissions` attribute should be a list of [FileSystemRights](http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemrights.aspx), [RegistryRights](http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.registryrights.aspx), or [CryptoKeyRights](http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.cryptokeyrights.aspx), for files/directories, registry keys, and certificate private keys, respectively. These commands will show you the values for the appropriate permissions for your object:
    
            [Enum]::GetValues([Security.AccessControl.FileSystemRights])
            [Enum]::GetValues([Security.AccessControl.RegistryRights])
            [Enum]::GetValues([Security.AccessControl.CryptoKeyRights])
    
        Beginning with Carbon 2.0, permissions are only granted if they don't exist on an item (inherited permissions are ignored).  If you always want to grant permissions, use the `Force` switch.  
    
        Before Carbon 2.0, this function returned any new/updated access rules set on `Path`. In Carbon 2.0 and later, use the `PassThru` switch to get an access rule object back (you'll always get one regardless if the permissions changed or not).
    
        By default, permissions allowing access are granted. Beginning in Carbon 2.3.0, you can grant permissions denying access by passing `Deny` as the value of the `Type` parameter.
    
        ## Directories and Registry Keys
    
        When setting permissions on a container (directory/registry key) you can control inheritance and propagation flags using the `ApplyTo` parameter. This parameter is designed to hide the complexities of the Windows' inheritance and propagation flags. There are 13 possible combinations.
    
        Given this tree
    
                C
               / \
              CC CL
             /  \
            GC  GL
    
        where
        
         * C is the **C**ontainer permissions are getting set on  
         * CC is a **C**hild **C**ontainer  
         * CL is a **C**hild **L**eaf  
         * GC is a **G**randchild **C**ontainer and includes all sub-containers below it  
         * GL is a **G**randchild **L**eaf  
        
        The `ApplyTo` parameter takes one of the following 13 values and applies permissions to:
        
         * **Container** - The container itself and nothing below it.
         * **SubContainers** - All sub-containers under the container, e.g. CC and GC. 
         * **Leaves** - All leaves under the container, e.g. CL and GL.
         * **ChildContainers** - Just the container's child containers, e.g. CC.
         * **ChildLeaves** - Just the container's child leaves, e.g. CL.
         * **ContainerAndSubContainers** - The container and all its sub-containers, e.g. C, CC, and GC.
         * **ContainerAndLeaves** - The container and all leaves under it, e.g. C and CL.
         * **SubContainerAndLeaves** - All sub-containers and leaves, but not the container itself, e.g. CC, CL, GC, and GL.
         * **ContainerAndChildContainers** - The container and all just its child containers, e.g. C and CC.
         * **ContainerAndChildLeaves** - The container and just its child leaves, e.g. C and CL.
         * **ContainerAndChildContainersAndChildLeaves** - The container and just its child containers/leaves, e.g. C, CC, and CL.
         * **ContainerAndSubContainersAndLeaves** - Everything, full inheritance/propogation, e.g. C, CC, GC, GL.  **This is the default.**
         * **ChildContainersAndChildLeaves**  - Just the container's child containers/leaves, e.g. CC and CL.
    
        The following table maps `ContainerInheritanceFlags` values to the actual `InheritanceFlags` and `PropagationFlags` values used:
             
            ContainerInheritanceFlags                   InheritanceFlags                 PropagationFlags
            -------------------------                   ----------------                 ----------------
            Container                                   None                             None
            SubContainers                               ContainerInherit                 InheritOnly
            Leaves                                      ObjectInherit                    InheritOnly
            ChildContainers                             ContainerInherit                 InheritOnly,
                                                                                         NoPropagateInherit
            ChildLeaves                                 ObjectInherit                    InheritOnly
            ContainerAndSubContainers                   ContainerInherit                 None
            ContainerAndLeaves                          ObjectInherit                    None
            SubContainerAndLeaves                       ContainerInherit,ObjectInherit   InheritOnly
            ContainerAndChildContainers                 ContainerInherit                 None
            ContainerAndChildLeaves                     ObjectInherit                    None
            ContainerAndChildContainersAndChildLeaves   ContainerInherit,ObjectInherit   NoPropagateInherit
            ContainerAndSubContainersAndLeaves          ContainerInherit,ObjectInherit   None
            ChildContainersAndChildLeaves               ContainerInherit,ObjectInherit   InheritOnly
        
        The above information adapated from [Manage Access to Windows Objects with ACLs and the .NET Framework](http://msdn.microsoft.com/en-us/magazine/cc163885.aspx#S3), published in the November 2004 copy of *MSDN Magazine*.
    
        If you prefer to speak in `InheritanceFlags` or `PropagationFlags`, you can use the `ConvertTo-ContainerInheritaceFlags` function to convert your flags into Carbon's flags.
    
        ## Certificate Private Keys/Key Containers
    
        When setting permissions on a certificate's private key/key container, if a certificate doesn't have a private key, it is ignored and no permissions are set. Since certificate's are always leaves, the `ApplyTo` parameter is ignored.
    
        When using the `-Clear` switch, note that the local `Administrators` account will always remain. In testing on Windows 2012 R2, we noticed that when `Administrators` access was removed, you couldn't read the key anymore. 
    
        .OUTPUTS
        System.Security.AccessControl.AccessRule. When setting permissions on a file or directory, a `System.Security.AccessControl.FileSystemAccessRule` is returned. When setting permissions on a registry key, a `System.Security.AccessControl.RegistryAccessRule` returned. When setting permissions on a private key, a `System.Security.AccessControl.CryptoKeyAccessRule` object is returned.
    
        .LINK
        Carbon_Permission
    
        .LINK
        ConvertTo-ContainerInheritanceFlags
    
        .LINK
        Disable-AclInheritance
    
        .LINK
        Enable-AclInheritance
    
        .LINK
        Get-Permission
    
        .LINK
        Revoke-Permission
    
        .LINK
        Test-Permission
    
        .LINK
        http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemrights.aspx
        
        .LINK
        http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.registryrights.aspx
        
        .LINK
        http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.cryptokeyrights.aspx
        
        .LINK
        http://msdn.microsoft.com/en-us/magazine/cc163885.aspx#S3    
        
        .EXAMPLE
        Grant-Permission -Identity ENTERPRISE\Engineers -Permission FullControl -Path C:\EngineRoom
    
        Grants the Enterprise's engineering group full control on the engine room.  Very important if you want to get anywhere.
    
        .EXAMPLE
        Grant-Permission -Identity ENTERPRISE\Interns -Permission ReadKey,QueryValues,EnumerateSubKeys -Path rklm:\system\WarpDrive
    
        Grants the Enterprise's interns access to read about the warp drive.  They need to learn someday, but at least they can't change anything.
        
        .EXAMPLE
        Grant-Permission -Identity ENTERPRISE\Engineers -Permission FullControl -Path C:\EngineRoom -Clear
        
        Grants the Enterprise's engineering group full control on the engine room.  Any non-inherited, existing access rules are removed from `C:\EngineRoom`.
        
        .EXAMPLE
        Grant-Permission -Identity ENTERPRISE\Engineers -Permission FullControl -Path 'cert:\LocalMachine\My\1234567890ABCDEF1234567890ABCDEF12345678'
        
        Grants the Enterprise's engineering group full control on the `1234567890ABCDEF1234567890ABCDEF12345678` certificate's private key/key container.
    
        .EXAMPLE
        Grant-Permission -Identity BORG\Locutus -Permission FullControl -Path 'C:\EngineRoom' -Type Deny
    
        Demonstrates how to grant deny permissions on an objecy with the `Type` parameter.
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        [OutputType([Security.AccessControl.AccessRule])]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The path on which the permissions should be granted.  Can be a file system, registry, or certificate path.
            $Path,
            
            [Parameter(Mandatory=$true)]
            [string]
            # The user or group getting the permissions.
            $Identity,
            
            [Parameter(Mandatory=$true)]
            [string[]]
            # The permission: e.g. FullControl, Read, etc.  For file system items, use values from [System.Security.AccessControl.FileSystemRights](http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemrights.aspx).  For registry items, use values from [System.Security.AccessControl.RegistryRights](http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.registryrights.aspx).
    		[Alias('Permissions')]
            $Permission,
            
            [Carbon.Security.ContainerInheritanceFlags]
            # How to apply container permissions.  This controls the inheritance and propagation flags.  Default is full inheritance, e.g. `ContainersAndSubContainersAndLeaves`. This parameter is ignored if `Path` is to a leaf item.
            $ApplyTo = ([Carbon.Security.ContainerInheritanceFlags]::ContainerAndSubContainersAndLeaves),
    
            [Security.AccessControl.AccessControlType]
            # The type of rule to apply, either `Allow` or `Deny`. The default is `Allow`, which will allow access to the item. The other option is `Deny`, which will deny access to the item.
            #
            # This parameter was added in Carbon 2.3.0.
            $Type = [Security.AccessControl.AccessControlType]::Allow,
            
            [Switch]
            # Removes all non-inherited permissions on the item.
            $Clear,
    
            [Switch]
            # Returns an object representing the permission created or set on the `Path`. The returned object will have a `Path` propery added to it so it can be piped to any cmdlet that uses a path. 
            #
            # The `PassThru` switch is new in Carbon 2.0.
            $PassThru,
    
            [Switch]
            # Grants permissions, even if they are already present.
            $Force
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
        
        $Path = Resolve-Path -Path $Path
        if( -not $Path )
        {
            return
        }
    
        $providerName = Get-PathProvider -Path $Path | Select-Object -ExpandProperty 'Name'
        if( $providerName -eq 'Certificate' )
        {
            $providerName = 'CryptoKey'
        }
    
        if( $providerName -ne 'Registry' -and $providerName -ne 'FileSystem' -and $providerName -ne 'CryptoKey' )
        {
            Write-Error "Unsupported path: '$Path' belongs to the '$providerName' provider.  Only file system, registry, and certificate paths are supported."
            return
        }
    
        $rights = $Permission | ConvertTo-ProviderAccessControlRights -ProviderName $providerName
        if( -not $rights )
        {
            Write-Error ('Unable to grant {0} {1} permissions on {2}: received an unknown permission.' -f $Identity,($Permission -join ','),$Path)
            return
        }
    
        if( -not (Test-Identity -Name $Identity ) )
        {
            Write-Error ('Identity ''{0}'' not found.' -f $Identity)
            return
        }
    
        $Identity = Resolve-IdentityName -Name $Identity
        
        if( $providerName -eq 'CryptoKey' )
        {
            Get-Item -Path $Path |
                ForEach-Object {
                    [Security.Cryptography.X509Certificates.X509Certificate2]$certificate = $_
    
                    if( -not $certificate.HasPrivateKey )
                    {
                        Write-Warning ('Certificate {0} ({1}; {2}) does not have a private key.' -f $certificate.Thumbprint,$certificate.Subject,$Path)
                        return
                    }
    
                    if( -not $certificate.PrivateKey )
                    {
                        Write-Error ('Access is denied to private key of certificate {0} ({1}; {2}).' -f $certificate.Thumbprint,$certificate.Subject,$Path)
                        return
                    }
    
                    [Security.AccessControl.CryptoKeySecurity]$keySecurity = $certificate.PrivateKey.CspKeyContainerInfo.CryptoKeySecurity
                    if( -not $keySecurity )
                    {
                        Write-Error ('Private key ACL not found for certificate {0} ({1}; {2}).' -f $certificate.Thumbprint,$certificate.Subject,$Path)
                        return
                    }
    
                    $rulesToRemove = @()
                    if( $Clear )
                    {
                        $rulesToRemove = $keySecurity.Access | 
                                            Where-Object { $_.IdentityReference.Value -ne $Identity } |
                                            # Don't remove Administrators access. 
                                            Where-Object { $_.IdentityReference.Value -ne 'BUILTIN\Administrators' }
                        if( $rulesToRemove )
                        {
                            $rulesToRemove | ForEach-Object { 
                                Write-Verbose ('[{0} {1}] [{1}]  {2} -> ' -f $certificate.IssuedTo,$Path,$_.IdentityReference,$_.CryptoKeyRights)
                                if( -not $keySecurity.RemoveAccessRule( $_ ) )
                                {
                                    Write-Error ('Failed to remove {0}''s {1} permissions on ''{2}'' (3) certificate''s private key.' -f $_.IdentityReference,$_.CryptoKeyRights,$Certificate.Subject,$Certificate.Thumbprint)
                                }
                            }
                        }
                    }
                    
                    $certPath = Join-Path -Path 'cert:' -ChildPath (Split-Path -NoQualifier -Path $certificate.PSPath)
    
                    $accessRule = New-Object 'Security.AccessControl.CryptoKeyAccessRule' ($Identity,$rights,$Type) |
                                    Add-Member -MemberType NoteProperty -Name 'Path' -Value $certPath -PassThru
    
                    if( $Force -or $rulesToRemove -or -not (Test-Permission -Path $certPath -Identity $Identity -Permission $Permission -Exact) )
                    {
                        $currentPerm = Get-Permission -Path $certPath -Identity $Identity
                        if( $currentPerm )
                        {
                            $currentPerm = $currentPerm."$($providerName)Rights"
                        }
                        Write-Verbose -Message ('[{0} {1}] [{2}]  {3} -> {4}' -f $certificate.IssuedTo,$certPath,$accessRule.IdentityReference,$currentPerm,$accessRule.CryptoKeyRights)
                        $keySecurity.SetAccessRule( $accessRule )
                        Set-CryptoKeySecurity -Certificate $certificate -CryptoKeySecurity $keySecurity -Action ('grant {0} {1} permission(s)' -f $Identity,($Permission -join ','))
                    }
    
                    if( $PassThru )
                    {
                        return $accessRule
                    }
                }
        }
        else
        {
            # We don't use Get-Acl because it returns the whole security descriptor, which includes owner information.
            # When passed to Set-Acl, this causes intermittent errors.  So, we just grab the ACL portion of the security descriptor.
            # See http://www.bilalaslam.com/2010/12/14/powershell-workaround-for-the-security-identifier-is-not-allowed-to-be-the-owner-of-this-object-with-set-acl/
            $currentAcl = (Get-Item $Path -Force).GetAccessControl("Access")
        
            $inheritanceFlags = [Security.AccessControl.InheritanceFlags]::None
            $propagationFlags = [Security.AccessControl.PropagationFlags]::None
            $testPermissionParams = @{ }
            if( Test-Path $Path -PathType Container )
            {
                $inheritanceFlags = ConvertTo-InheritanceFlag -ContainerInheritanceFlag $ApplyTo
                $propagationFlags = ConvertTo-PropagationFlag -ContainerInheritanceFlag $ApplyTo
                $testPermissionParams.ApplyTo = $ApplyTo
            }
            else
            {
                if( $PSBoundParameters.ContainsKey( 'ApplyTo' ) )
                {
                    Write-Warning "Can't apply inheritance/propagation rules to a leaf. Please omit `ApplyTo` parameter when `Path` is a leaf."
                }
            }
        
            $rulesToRemove = $null
            $Identity = Resolve-Identity -Name $Identity
            if( $Clear )
            {
                $rulesToRemove = $currentAcl.Access |
                                    Where-Object { $_.IdentityReference.Value -ne $Identity } |
                                    Where-Object { -not $_.IsInherited }
            
                if( $rulesToRemove )
                {
                    foreach( $ruleToRemove in $rulesToRemove )
                    {
                        Write-Verbose ('[{0}] [{1}]  {2} -> ' -f $Path,$Identity,$ruleToRemove."$($providerName)Rights")
                        [void]$currentAcl.RemoveAccessRule( $ruleToRemove )
                    }
                }
            }
    
            $accessRule = New-Object "Security.AccessControl.$($providerName)AccessRule" $Identity,$rights,$inheritanceFlags,$propagationFlags,$Type |
                            Add-Member -MemberType NoteProperty -Name 'Path' -Value $Path -PassThru
    
            $missingPermission = -not (Test-Permission -Path $Path -Identity $Identity -Permission $Permission @testPermissionParams -Exact)
    
            $setAccessRule = ($Force -or $missingPermission)
            if( $setAccessRule )
            {
                $currentAcl.SetAccessRule( $accessRule )
            }
    
            if( $rulesToRemove -or $setAccessRule )
            {
                $currentPerm = Get-Permission -Path $Path -Identity $Identity
                if( $currentPerm )
                {
                    $currentPerm = $currentPerm."$($providerName)Rights"
                }
                Write-Verbose -Message ('[{0}] [{1}]  {2} -> {3}' -f $Path,$accessRule.IdentityReference,$currentPerm,$accessRule."$($providerName)Rights")
                Set-Acl -Path $Path -AclObject $currentAcl
            }
    
            if( $PassThru )
            {
                return $accessRule
            }
        }
    }
    
    Set-Alias -Name 'Grant-Permissions' -Value 'Grant-Permission'
    
    
  • Carbon\Functions\Grant-Privilege.ps1 Show
    # 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
            }
        }
    }
    
    
  • Carbon\Functions\Grant-ServiceControlPermission.ps1 Show
    # 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-ServiceControlPermission
    {
        <#
        .SYNOPSIS
        Grants a user/group permission to start/stop (i.e. use PowerShell's `*-Service` cmdlets) a service.
    
        .DESCRIPTION
        By default, only Administrators are allowed to control a service. You may notice that when running the `Stop-Service`, `Start-Service`, or `Restart-Service` cmdlets as a non-Administrator, you get permissions errors. That's because you need to correct permissions.  This function grants just the permissions needed to use PowerShell's `Stop-Service`, `Start-Service`, and `Restart-Service` cmdlets to control a service.
    
        .LINK
        Get-ServicePermission
        
        .LINK
        Grant-ServicePermission
        
        .LINK
        Revoke-ServicePermission
        
        .EXAMPLE
        Grant-ServiceControlPermission -ServiceName CCService -Identity INITRODE\Builders
    
        Grants the INITRODE\Builders group permission to control the CruiseControl.NET service.
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The name of the service.
            $ServiceName,
            
            [Parameter(Mandatory=$true)]
            [string]
            # The user/group name being given access.
            $Identity
        )
       
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        if( $pscmdlet.ShouldProcess( $ServiceName, "grant control service permissions to '$Identity'" ) )
        {
            Grant-ServicePermission -Name $ServiceName -Identity $Identity -QueryStatus -EnumerateDependents -Start -Stop
        }
    }
    
    
  • Carbon\Functions\Grant-ServicePermission.ps1 Show
    # 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-ServicePermission
    {
        <#
        .SYNOPSIS
        Grants permissions for an identity against a service.
        
        .DESCRIPTION
        By default, only Administators are allowed to manage a service.  Use this function to grant specific identities permissions to manage a specific service.
        
        If you just want to grant a user the ability to start/stop/restart a service using PowerShell's `Start-Service`, `Stop-Service`, or `Restart-Service` cmdlets, use the `Grant-ServiceControlPermissions` function instead.
        
        Any previous permissions are replaced.
        
        .LINK
        Get-ServicePermission
        
        .LINK
        Grant-ServiceControlPermissions
        
        .EXAMPLE
        Grant-ServicePermission -Identity FALCON\Chewbacca -Name Hyperdrive -QueryStatus -EnumerateDependents -Start -Stop
        
        Grants Chewbacca the permissions to query, enumerate dependents, start, and stop the `Hyperdrive` service.  Coincedentally, these are the permissions that Chewbacca nees to run `Start-Service`, `Stop-Service`, `Restart-Service`, and `Get-Service` cmdlets against the `Hyperdrive` service.
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The name of the service to grant permissions to.
            $Name,
            
            [Parameter(Mandatory=$true)]
            [string]
            # The identity to grant permissions for.
            $Identity,
            
            [Parameter(Mandatory=$true,ParameterSetName='FullControl')]
            [Switch]
            # Grant full control on the service
            $FullControl,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to query the service's configuration.
            $QueryConfig,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to change the service's permission.
            $ChangeConfig,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to query the service's status.
            $QueryStatus,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permissionto enumerate the service's dependent services.
            $EnumerateDependents,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to start the service.
            $Start,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to stop the service.
            $Stop,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to pause/continue the service.
            $PauseContinue,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to interrogate the service (i.e. ask it to report its status immediately).
            $Interrogate,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to run the service's user-defined control.
            $UserDefinedControl,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to delete the service.
            $Delete,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to query the service's security descriptor.
            $ReadControl,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to set the service's discretionary access list.
            $WriteDac,
            
            [Parameter(ParameterSetName='PartialControl')]
            [Switch]
            # Grants permission to modify the group and owner of a service.
            $WriteOwner
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $account = Resolve-Identity -Name $Identity
        if( -not $account )
        {
            return
        }
        
        if( -not (Assert-Service -Name $Name) )
        {
            return
        }
        
        $accessRights = [Carbon.Security.ServiceAccessRights]::FullControl
        if( $pscmdlet.ParameterSetName -eq 'PartialControl' )
        {
            $accessRights = 0
            [Enum]::GetValues( [Carbon.Security.ServiceAccessRights] ) |
                Where-Object { $PSBoundParameters.ContainsKey( $_ ) } |
                ForEach-Object { $accessRights = $accessRights -bor [Carbon.Security.ServiceAccessRights]::$_ }
        }
        
        $dacl = Get-ServiceAcl -Name $Name
        $dacl.SetAccess( [Security.AccessControl.AccessControlType]::Allow, $account.Sid, $accessRights, 'None', 'None' )
        
        Set-ServiceAcl -Name $Name -DACL $dacl
    }
    
    
    
  • Carbon\Functions\Initialize-Lcm.ps1 Show
    # 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
    
        ***NOTE: You can't use `Initialize-Lcm` to put the local configuration manager in pull mode on Windows 2016 or later.***
        
        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.
    
        This function is not available in 32-bit PowerShell 4 processes on 64-bit operating systems.
    
        `Initialize-Lcm` is new in Carbon 2.0.
    
        You cannot use `Initialize-Lcm
    
        .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. You can't do this on Windows 2016 or later.
    
        .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. You can't do this on Windows 2016 or later.
    
        .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( $PSCmdlet.ParameterSetName -match '^Pull(File|Web)DownloadManager' )
        {
            if( [Environment]::OSVersion.Version.Major -ge 10 )
            {
                Write-Error -Message ('Initialize-Lcm can''t configure the local configuration manager to use the file or web download manager on Windows Server 2016 or later.')
                return
            }
        }
    
        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
        }
    }
    
  • Carbon\Functions\Install-Certificate.ps1 Show
    # 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 [email protected]
        
        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*' )
        {   
            $resolvedPath = Resolve-Path -Path $Path        
            if( -not $resolvedPath )
            {
                return
            }
    
            $Path = $resolvedPath.ProviderPath
            
            $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
    }
    
    
  • Carbon\Functions\Install-Directory.ps1 Show
    # 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
        }
    }
  • Carbon\Functions\Install-FileShare.ps1 Show
    # 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-FileShare
    {
        <#
        .SYNOPSIS
        Installs a file/SMB share.
    
        .DESCRIPTION
        The `Install-FileShare` function installs a new file/SMB share. If the share doesn't exist, it is created. In Carbon 2.0, if a share does exist, its properties and permissions are updated in place, unless the share's path needs to change. Changing a share's path requires deleting and re-creating. Before Carbon 2.0, shares were always deleted and re-created.
    
        Use the `FullAccess`, `ChangeAccess`, and `ReadAccess` parameters to grant full, change, and read sharing permissions on the share. Each parameter takes a list of user/group names. If you don't supply any permissions, `Everyone` will get `Read` access. Permissions on existing shares are cleared before permissions are granted. Permissions don't apply to the file system, only to the share. Use `Grant-Permission` to grant file system permissions. 
    
        Before Carbon 2.0, this function was called `Install-SmbShare`.
    
        .LINK
        Get-FileShare
    
        .LINK
        Get-FileSharePermission
    
        .LINK
        Grant-Permission
    
        .LINK
        Test-FileShare
    
        .LINK
        Uninstall-FileShare
    
        .EXAMPLE
        Install-Share -Name TopSecretDocuments -Path C:\TopSecret -Description 'Share for our top secret documents.' -ReadAccess "Everyone" -FullAccess "Analysts"
    
        Shares the C:\TopSecret directory as `TopSecretDocuments` and grants `Everyone` read access and `Analysts` full control.  
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The share's name.
            $Name,
            
            [Parameter(Mandatory=$true)]
            [string]
            # The path to the share.
            $Path,
                
            [string]
            # A description of the share
            $Description = '',
            
            [string[]]
            # The identities who have full access to the share.
            $FullAccess = @(),
            
            [string[]]
            # The identities who have change access to the share.
            $ChangeAccess = @(),
            
            [string[]]
            # The identities who have read access to the share
            $ReadAccess = @(),
    
            [Switch]
            # Deletes the share and re-creates it, if it exists. Preserves default beheavior 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
    
        function New-ShareAce
        {
            param(
                [Parameter(Mandatory=$true)]
                [AllowEmptyCollection()]
                [string[]]
                # The identity 
                $Identity,
    
                [Carbon.Security.ShareRights]
                # The rights to grant to Identity.
                $ShareRight
            )
    
            Set-StrictMode -Version 'Latest'
    
            foreach( $identityName in $Identity )
            {
                $trustee = ([wmiclass]'Win32_Trustee').CreateInstance()
                [Security.Principal.SecurityIdentifier]$sid = Resolve-Identity -Name $identityName | Select-Object -ExpandProperty 'Sid'
                if( -not $sid )
                {
                    continue
                }
    
                $sidBytes = New-Object 'byte[]' $sid.BinaryLength
                $sid.GetBinaryForm( $sidBytes, 0)
    
                $trustee.Sid = $sidBytes
    
                $ace = ([wmiclass]'Win32_Ace').CreateInstance()
                $ace.AccessMask = $ShareRight
                $ace.AceFlags = 0
                $ace.AceType = 0
                $ace.Trustee = $trustee
    
                $ace
            }
        }
    
        $errors = @{
                    [uint32]2 = 'Access Denied';
                    [uint32]8 = 'Unknown Failure';
                    [uint32]9 = 'Invalid Name';
                    [uint32]10 = 'Invalid Level';
                    [uint32]21 = 'Invalid Parameter';
                    [uint32]22 = 'Duplicate Share';
                    [uint32]23 = 'Restricted Path';
                    [uint32]24 = 'Unknown Device or Directory';
                    [uint32]25 = 'Net Name Not Found';
                }
    
        $Path = Resolve-FullPath -Path $Path
        $Path = $Path.Trim('\\')
        # When sharing drives, path must end with \. Otherwise, it shouldn't.
        if( $Path -eq (Split-Path -Qualifier -Path $Path ) )
        {
            $Path = Join-Path -Path $Path -ChildPath '\'
        }
    
        if( (Test-FileShare -Name $Name) )
        {
            $share = Get-FileShare -Name $Name
            [bool]$delete = $false
            
            if( $Force )
            {
                $delete = $true
            }
    
            if( $share.Path -ne $Path )
            {
                Write-Verbose -Message ('[SHARE] [{0}] Path         {1} -> {2}.' -f $Name,$share.Path,$Path)
                $delete = $true
            }
    
            if( $delete )
            {
                Uninstall-FileShare -Name $Name
            }
        }
    
        $shareAces = Invoke-Command -ScriptBlock {
                                                    New-ShareAce -Identity $FullAccess -ShareRight FullControl
                                                    New-ShareAce -Identity $ChangeAccess -ShareRight Change
                                                    New-ShareAce -Identity $ReadAccess -ShareRight Read
                                               }
        if( -not $shareAces )
        {
            $shareAces = New-ShareAce -Identity 'Everyone' -ShareRight Read
        }
    
        # if we don't pass a $null security descriptor, default Everyone permissions aren't setup correctly, and extra admin rights are slapped on.
        $shareSecurityDescriptor = ([wmiclass] "Win32_SecurityDescriptor").CreateInstance() 
        $shareSecurityDescriptor.DACL = $shareAces
        $shareSecurityDescriptor.ControlFlags = "0x4"
    
        if( -not (Test-FileShare -Name $Name) )
        {
            if( -not (Test-Path -Path $Path -PathType Container) )
            {
                New-Item -Path $Path -ItemType Directory -Force | Out-String | Write-Verbose
            }
        
            $shareClass = Get-WmiObject -Class 'Win32_Share' -List
            Write-Verbose -Message ('[SHARE] [{0}]              Sharing {1}' -f $Name,$Path)
            $result = $shareClass.Create( $Path, $Name, 0, $null, $Description, $null, $shareSecurityDescriptor )
            if( $result.ReturnValue )
            {
                Write-Error ('Failed to create share ''{0}'' (Path: {1}). WMI returned error code {2} which means: {3}.' -f $Name,$Path,$result.ReturnValue,$errors[$result.ReturnValue])
                return
            }
        }
        else
        {
            $share = Get-FileShare -Name $Name
            $updateShare = $false
            if( $share.Description -ne $Description )
            {
                Write-Verbose -Message ('[SHARE] [{0}] Description  {1} -> {2}' -f $Name,$share.Description,$Description)
                $updateShare = $true
            }
    
            # Check if the share is missing any of the new ACEs.
            foreach( $ace in $shareAces )
            {
                $identityName = Resolve-IdentityName -SID $ace.Trustee.SID
                $permission = Get-FileSharePermission -Name $Name -Identity $identityName
    
                if( -not $permission )
                {
                    Write-Verbose -Message ('[SHARE] [{0}] Access       {1}:  -> {2}' -f $Name,$identityName,([Carbon.Security.ShareRights]$ace.AccessMask))
                    $updateShare = $true
                }
                elseif( [int]$permission.ShareRights -ne $ace.AccessMask )
                {
                    Write-Verbose -Message ('[SHARE] [{0}] Access       {1}: {2} -> {3}' -f $Name,$identityName,$permission.ShareRights,([Carbon.Security.ShareRights]$ace.AccessMask))
                    $updateShare = $true
                }
            }
    
            # Now, check that there aren't any existing ACEs that need to get deleted.
            $existingAces = Get-FileSharePermission -Name $Name
            foreach( $ace in $existingAces )
            {
                $identityName = $ace.IdentityReference.Value
    
                $existingAce = $ace
                if( $shareAces )
                {
                    $existingAce = $shareAces | Where-Object { 
                                                            $newIdentityName = Resolve-IdentityName -SID $_.Trustee.SID
                                                            return ( $newIdentityName -eq $ace.IdentityReference.Value )
                                                        }
                }
    
                if( -not $existingAce )
                {
                    Write-Verbose -Message ('[SHARE] [{0}] Access       {1}: {2} ->' -f $Name,$identityName,$ace.ShareRights)
                    $updateShare = $true
                }
            }
    
            if( $updateShare )
            {
                $result = $share.SetShareInfo( $share.MaximumAllowed, $Description, $shareSecurityDescriptor )
                if( $result.ReturnValue )
                {
                    Write-Error ('Failed to create share ''{0}'' (Path: {1}). WMI returned error code {2} which means: {3}' -f $Name,$Path,$result.ReturnValue,$errors[$result.ReturnValue])
                    return
                }
            }
        }
    }
    
    Set-Alias -Name 'Install-SmbShare' -Value 'Install-FileShare'
    
  • Carbon\Functions\Install-Group.ps1 Show
    # 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()
            }
    
        }
    }
    
    
  • Carbon\Functions\Install-IisApplication.ps1 Show
    # 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
        }
    
    }
    
    
  • Carbon\Functions\Install-IisAppPool.ps1 Show
    # 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. Use an empty string if you're running .NET Core or to set the .NET framework version to `No Managed Code`.
    
        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`. Use an empty string if you're using .NET Core or to set the .NET framework version to `No Managed Code`.
            $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
        }
    }
    
    
  • Carbon\Functions\Install-IisVirtualDirectory.ps1 Show
    # 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()
        }
    }
    
    
  • Carbon\Functions\Install-IisWebsite.ps1 Show
    # 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 -Binding '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
        }
    }
    
    
  • Carbon\Functions\Install-Junction.ps1 Show
    # 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
            }
        }
    }
    
    
  • Carbon\Functions\Install-Msi.ps1 Show
    # 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'
    
  • Carbon\Functions\Install-Msmq.ps1 Show
    # 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 )
        }
    }
    
    
  • Carbon\Functions\Install-MsmqMessageQueue.ps1 Show
    # 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-MsmqMessageQueue
    {
        <#
        .SYNOPSIS
        Installs an MSMQ queue.
    
        .DESCRIPTION
        Creates a new queue with name `Name`.  If a queue with that name already exists, it is deleted, and a new queue is created. 
    
        If the queue needs to be private, pass the `Private` switch.  If it needs to be transactional, set the `Transactional` switch.
        
        .EXAMPLE
        Install-MsmqMessageQueue -Name MovieQueue
    
        Installs a public, non-transactional `MovieQueue`.
    
        .EXAMPLE
        Install-MsmqMessageQueue -Name CriticsQueue -Private -Transactional
    
        Installs a private, transactional `CriticsQueue` queue.
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The name of the queue.
            $Name,
            
            [Switch]
            # Makes a private queue.
            $Private,
            
            [Switch]
            # Makes a transactional queue.
            $Transactional
        )
        
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $queueArgs = @{ Name = $Name ; Private = $Private }
        $path = Get-MsmqMessageQueuePath @queueArgs 
        
        $cmdletArgs = @{ }
        if( $PSBoundParameters.ContainsKey( 'WhatIf' ) )
        {
            $cmdletArgs.WhatIf = $true
        }
        
        $logMessage = "MSMQ message queue '$Name'."
        if( Test-MsmqMessageQueue @queueArgs )
        {
            Write-Verbose "Re-creating $logMessage"
            Uninstall-MsmqMessageQueue @queueArgs @cmdletArgs
        }
        else
        {
            Write-Verbose "Creating $logMessage"
        }
        
        $MaxWait = [TimeSpan]'0:00:10'
        $endAt = (Get-Date) + $MaxWait
        $created = $false
        if( $pscmdlet.ShouldProcess( $path, 'install MSMQ queue' ) )
        {
            # If you remove a queue, sometimes you can't immediately re-create it.  So, we keep trying until we can.
            do
            {
                try
                {
                    # Capture the return object, otherwise it gets sent down the pipeline and causes an error
                    $queue = [Messaging.MessageQueue]::Create( $path, $Transactional )
                    $created = $true
                    break
                }
                catch 
                { 
                    if( $_.Exception.Message -like '*A workgroup installation computer does not support the operation.*' )
                    {
                        Write-Error ("Can't create MSMSQ queues on this computer.  {0}" -f $_.Exception.Message)
                        return
                    }
                }
                Start-Sleep -Milliseconds 100
            }
            while( -not $created -and (Get-Date) -lt $endAt )
            
            if( -not $created )
            {
                Write-Error ('Unable to create MSMQ queue {0}.' -f $path)
                return
            }
            
            $endAt = (Get-Date) + $MaxWait
            $exists = $false
            do
            {
                Start-Sleep -Milliseconds 100
                if( (Test-MsmqMessageQueue @queueArgs) )
                {
                    $exists = $true
                    break
                }
            }
            while( (Get-Date) -lt $endAt -and -not $exists )
            
            if( -not $exists )
            {
                Write-Warning ('MSMSQ queue {0} created, but can''t be found.  Please double-check that the queue was created.' -f $path)
            }
        }
    }
    
    
  • Carbon\Functions\Install-PerformanceCounter.ps1 Show
    # 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 )
        }
    }
    
    
  • Carbon\Functions\Install-RegistryKey.ps1 Show
    # 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
        }
    }
    
    
    
  • Carbon\Functions\Install-ScheduledTask.ps1 Show
    # 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]
            # If the user is an administrator, runs the task with full administrator rights. The default is to run with limited administrative privileges. 
            #
            # If UAC is enabled, an administrator has two security tokens: a filtered token that gets used by default and grants standard user rights and a full token that grants administrative rights that is only used when a program is "Run as administrator". Using this switch runs the scheduled task with the adminisrators full token. (Information taken from [How does "Run with the highest privileges" really work in Task Scheduler ?](https://social.technet.microsoft.com/Forums/windows/en-US/7167bb31-f375-4f77-b430-0339092e16b9/how-does-run-with-the-highest-privileges-really-work-in-task-scheduler-).)
            $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.Count -eq 1 -and [Enum]::IsDefined([DayOfWeek],$DayOfWeek[0]) )
                {
                    [void]$parameters.Add( (ConvertTo-SchtasksCalendarNameList $DayOfWeek[0]) )
                }
                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
            }
        }
    }
    
  • Carbon\Functions\Install-Service.ps1 Show
    # 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. If a service is stopped when configuration begins, it remains stopped when configuration ends. To start the service if it is stopped, use the `-EnsureRunning` switch (which was added in version 2.5.0).
    
        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 -StartupType Automatic -Delayed
    
        Demonstrates how to set a service startup typemode to automatic delayed. Set the `StartupType` parameter to `Automatic` and provide the `Delayed` switch. This behavior was added in Carbon 2.5.
    
        .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).
    
        .EXAMPLE
        Install-Service -Name DeathStar -Path C:\ALongTimeAgo\InAGalaxyFarFarAway\DeathStar.exe -EnsureRunning
    
        Demonstrates how to ensure a service gets started after installation/configuration. Normally, `Install-Service` leaves the service in whatever state the service was in. The `EnsureRunnnig` switch will attempt to start the service even if it was stopped to begin with.
        #>
        [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.
            #
            # To start the service as automatic delayed, use the `-Delayed` switch and set this parameter to `Automatic`. The ability to set a service's startup type to automatic delayed was added in Carbon 2.5.
            $StartupType = [ServiceProcess.ServiceStartMode]::Automatic,
    
            [Switch]
            # When the startup type is automatic, further configure the service start type to be automatic delayed. This parameter is ignored unless `StartupType` is `Automatic`.
            #
            # This switch was added in Carbon 2.5.
            $Delayed,
            
            [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,
    
            [Switch]
            # Start the service after install/configuration if it is not running. This parameter was added in Carbon 2.5.0.
            $EnsureRunning
        )
    
        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( $StartupType -eq [ServiceProcess.ServiceStartMode]::Automatic -and $Delayed -ne $serviceConfig.DelayedAutoStart )
            {
                Write-Verbose ('[{0}] DelayedAutoStart  {1} -> {2}' -f $Name,$service.DelayedAutoStart,$Delayed)
                $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
            }
    
            $currentIdentity = Resolve-Identity $serviceConfig.UserName
            if( $currentIdentity.FullName -ne $identity.FullName )
            {
                Write-Verbose ('[{0}] UserName          {1} -> {2}' -f $Name,$currentIdentity.FullName,$identity.FullName)
                $doinstall = $true
            }
        }
        else
        {
            $doInstall = $true
        }
    
        try
        {
            if( -not $doInstall )
            {
                Write-Debug -Message ('Skipping {0} service configuration: settings unchanged.' -f $Name)
                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 [ServiceProcess.ServiceStartMode]::Automatic -and $Delayed )
            {
                $startArg = 'delayed-auto'
            }
            elseif( $StartupType -eq [ServiceProcess.ServiceStartMode]::Manual )
            {
                $startArg = 'demand'
            }
            elseif( $StartupType -eq [ServiceProcess.ServiceStartMode]::Disabled )
            {
                $startArg = 'disabled'
            }
        
            $passwordArgName = ''
            $passwordArgValue = ''
            if( $PSCmdlet.ParameterSetName -like 'CustomAccount*' )
            {
                if( $Credential )
                {
                    $passwordArgName = 'password='
                    $passwordArgValue = $Credential.GetNetworkCredential().Password -replace '"', '\"'
                }
            
                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
                                       )
    
            if( -not $EnsureRunning )
            {
                $EnsureRunning = ($StartupType -eq [ServiceProcess.ServiceStartMode]::Automatic)
            }
    
            if( $service )
            {
                $EnsureRunning = ( $EnsureRunning -or ($serviceIsRunningStatus -contains $service.Status) )
                if( $StartupType -eq [ServiceProcess.ServiceStartMode]::Disabled )
                {
                    $EnsureRunning = $false
                }
    
                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 ("Failed 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 ("Failed 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
                }
            }
        }
        finally
        {
            if( $EnsureRunning )
            {
                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. To always start a service after configuring it, use the -EnsureRunning switch.' -f $Name,$StartupType)
            }
    
            if( $PassThru )
            {
                Get-Service -Name $Name -ErrorAction Ignore
            }
        }
    }
    
    
  • Carbon\Functions\Install-User.ps1 Show
    # 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()
            }
        }
    }
    
    
  • Carbon\Functions\Install-WindowsFeature.ps1 Show
    # 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'
    }
  • Carbon\Functions\Invoke-AppCmd.ps1 Show
    # 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."
        }
    }
    
    
  • Carbon\Functions\Invoke-ConsoleCommand.ps1 Show
    # 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
        }
    }
    
  • Carbon\Functions\Invoke-PowerShell.ps1 Show
    # 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, script, command, or encoded command under a new `powershell.exe` process.
        
        .DESCRIPTION
    
        The `Invoke-PowerShell` scripts executes `powershell.exe`. All processes are started with powershell.exe's `-NoProfile` paramter. You can specify values for powershell.exe's `OutputFormat`, `ExecutionPolicy`, and `NonInteractive` paramters via parameters of the same name on the `Invoke-PowerShell` function. Use the `Runtime` parameter to run `powershell.exe` version 2.
        
        To run a script, pass the path to the script with the `-FilePath` paramter. Pass any script arguments with the `ArgumentList` parameter. You must escape any parameters. They are passed to `powershell.exe` as-is.
        
        To run a script block, pass the script block with the `-ScriptBlock` parameter. Pass any script block arguments with the `ArgumentList` parameter. You must escape any parameters. They are passed to `powershell.exe` as-is.
        
        To run a command (Carbon 2.3.0 and later only), pass the command (i.e. string of PowerShell code) with the `Command` parameter. Any arguments to your command must be in the command itself. You must do any escaping.
        
        To run an encoded command (Carbon 2.3.0 and later only), pass the command (i.e. string of PowerShell code) with the `Command` parameter and the `-Encode` switch. `Invoke-PowerShell` will base-64 encode your command for you and pass it to `powershell.exe` with its `-EncodedCommand` parameter.
        
        Beginning in Carbon 2.3.0, you can run scripts, commands, and encoded commands as another user. Pass that user's credentials with the `Credential` parameter.
        
        On 64-bit operating systems, use the `-x86` switch to run the new `powershell.exe` process under 32-bit PowerShell. If this switch is ommitted, `powershell.exe` will be run under a 64-bit PowerShell process (even if called from a 32-bit process). On 32-bit operating systems, this switch is ignored.
        
        The `Runtime` paramter controls what version of the .NET framework `powershell.exe` should use. Pass `v2.0` and `v4.0` to run under .NET versions 2.0 or 4.0, respectivey. Those frameworks must be installed. When running under PowerShell 2, `Invoke-PowerShell` uses a temporary [activation configuration file](https://msdn.microsoft.com/en-us/library/ff361644(v=vs.100).aspx) to force PowerShell 2 to use .NET 4. When run under PowerShell 3 and later, `powershell.exe` is run with the `-Version` switch set to `2.0` to run `powershell.exe` under .NET 2.
    
        If using PowerShell v3.0 or later with a version of Carbon before 2.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.
        
        .EXAMPLE
        Invoke-PowerShell -ScriptBlock { $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 -ScriptBlock { $PSVersionTable } -x86
        
        Runs a 32-bit PowerShell process, return the $PSVersionTable from that process.
        
        .EXAMPLE
        Invoke-PowerShell -ScriptBlock { $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.
    
        .EXAMPLE
        Invoke-PowerShell -FilePath Get-PsVersionTable.ps1 -Credential $cred
    
        Demonstrates that you can run PowerShell scripts as a specific user with the `Credential` parameter.
    
        .EXAMPLE
        Invoke-PowerShell -FilePath Get-PsVersionTable.ps1 -Credential $cred
    
        Demonstrates that you can run PowerShell scripts as a specific user with the `Credential` parameter.
    
        .EXAMPLE 
        Invoke-PowerShell -Command '$PSVersionTable'
        
        Demonstrates how to run a PowerShell command contained in a string. You are responsible for quoting things correctly.
    
        .EXAMPLE
        Invoke-PowerShell -Command '$PSVersionTable' -Encode
    
        Demonstrates how to run a base-64 encode then run PowerShell command contained in a string. This runs the command using PowerShell's `-EncodedCommand` parameter. `Invoke-PowerShell` does the base-64 encoding for you.
    
        .EXAMPLE
        Invoke-PowerShell -Command '$env:USERNAME' -Credential $credential
    
        Demonstrates how to run a PowerShell command as another user. Uses `Start-Process` to launch `powershell.exe` as the user. 
        #>
        [CmdletBinding(DefaultParameterSetName='ScriptBlock')]
        param(
            [Parameter(Mandatory=$true,ParameterSetName='ScriptBlock')]
            [ScriptBlock]
            # The script block to pass to `powershell.exe`.
            $ScriptBlock,
            
            [Parameter(Mandatory=$true,ParameterSetName='Command')]
            [object]
            # The command to run, as a string. Passed to PowerShell.exe as the value to the `-Command` parameter. 
            #
            # Use the `-Encode` switch to avoid complicated quoting, and have `Invoke-PowerShell` encode this command for you and pass it to powershell.exe's `-EncodedCommand parameter.
            #
            # This parameter was introduced in Carbon 2.3.0. In previous versions, this parameter was an alias to the `ScriptBlock` parameter. To maintain backwards-compatibility, if you pass a `ScriptBlock` to this parameter, `Invoke-PowerShell` will run the script block as a script block. In the next major version of Carbon, this parameter will stop accepting `ScriptBlock` objects.
            $Command,
    
            [Parameter(Mandatory=$true,ParameterSetName='FilePath')]
            [string]
            # The script to run.
            $FilePath,
    
            [Parameter(ParameterSetName='Command')]
            [Parameter(ParameterSetName='ScriptBlock')]
            [Parameter(ParameterSetName='FilePath')]
            [object[]]
            [Alias('Args')]
            # Any arguments to pass to the script or command. These *are not* powershell.exe arguments. They are passed to powershell.exe as-is, so you'll need to escape them.
            $ArgumentList,
    
            [Parameter(ParameterSetName='Command')]
            [Switch]
            # Base-64 encode the command in `Command` and run it with powershell.exe's `-EncodedCommand` switch.
            #
            # This parameter was added in Carbon 2.3.0.
            $Encode,
            
            [string]
            # Determines how output from the PowerShel command is formatted. The value of this parameter is passed as-is to `powershell.exe` with its `-OutputFormat` paramter.
            $OutputFormat,
    
            [Microsoft.PowerShell.ExecutionPolicy]
            # The execution policy to use when running `powershell.exe`. Passed to `powershell.exe` with its `-ExecutionPolicy` parameter.
            $ExecutionPolicy,
    
            [Switch]
            # Run `powershell.exe` non-interactively. This passes the `-NonInteractive` switch to powershell.exe.
            $NonInteractive,
    
            [Switch]
            # Run the x86 (32-bit) version of PowerShell. if not provided, the version which matches the OS architecture is used, *regardless of the architecture of the currently running process*. I.e. this command is run under a 32-bit PowerShell on a 64-bit operating system, without this switch, `Invoke-Command` will start a 64-bit `powershell.exe`.
            $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.
            #
            # Beginning with Carbon 2.3.0, this parameter is ignored, since Carbon 2.0 and later only supports PowerShell 4 and you can't run PowerShell 4 under .NET 2.0. 
            #
            # This parameter is OBSOLETE and will be removed in a future major version of Carbon.
            $Runtime,
    
            [Parameter(ParameterSetName='FilePath')]
            [Parameter(ParameterSetName='Command')]
            [pscredential]
            # Run `powershell.exe` as a specific user. Pass that user's credentials with this parameter.
            #
            # This parameter is new in Carbon 2.3.0.
            $Credential
        )
        
        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 = @()
            }
    
            $runningAScriptBlock = $PSCmdlet.ParameterSetName -eq 'ScriptBlock' 
            if( $PSCmdlet.ParameterSetName -eq 'Command' -and $Command -is [scriptblock] )
            {
                Write-Warning -Message ('Passing a script block to the Command parameter is OBSOLETE and will be removed in a future major version of Carbon. Use the `ScriptBlock` parameter instead.')
                $ScriptBlock = $Command
                $runningAScriptBlock = $true
                if( $Credential )
                {
                    Write-Error -Message ('It looks like you''re trying to run a script block as another user. `Start-Process` is used to start powershell.exe as that user. Start-Process requires all arguments to be strings. Converting a script block to a string automatically is unreliable. Please convert the script block to a command string or omit the Credential parameter.')
                    return
                }
            }
    
            $powerShellArgs = Invoke-Command -ScriptBlock {
                if( $powerShellv3Installed -and $Runtime -eq 'v2.0' )
                {
                    '-Version'
                    '2.0'
                }
    
                # Can't run a script block in non-interactive mode. Because reasons.
                if( $NonInteractive -and -not $runningAScriptBlock )
                {
                    '-NonInteractive'
                }
    
                '-NoProfile'
    
                if( $OutputFormat )
                {
                    '-OutputFormat'
                    $OutputFormat
                }
    
                if( $ExecutionPolicy -and $PSCmdlet.ParameterSetName -ne 'ScriptBlock' )
                {
                    '-ExecutionPolicy'
                    $ExecutionPolicy
                }
            }
    
            if( $runningAScriptBlock )
            {
                Write-Debug -Message ('& {0} {1} -Command {2} -Args {3}' -f $psPath,($powerShellArgs -join ' '),$ScriptBlock,($ArgumentList -join ' '))
                & $psPath $powerShellArgs -Command $ScriptBlock -Args $ArgumentList
                Write-Debug -Message ('LASTEXITCODE: {0}' -f $LASTEXITCODE)
            }
            elseif( $PSCmdlet.ParameterSetName -eq 'FilePath' )
            {
                if( $Credential )
                {
                    Start-PowerShellProcess -CommandLine ('{0} -File "{1}" {2}' -f ($powerShellArgs -join " "),$FilePath,($ArgumentList -join " ")) -Credential $Credential
                }
                else
                {
                    Write-Debug ('{0} {1} -File {2} {3}' -f $psPath,($powerShellArgs -join " "),$FilePath,($ArgumentList -join ' '))
                    & $psPath $powerShellArgs -File $FilePath $ArgumentList
                    Write-Debug ('LASTEXITCODE: {0}' -f $LASTEXITCODE)
                }
            }
            else
            {
                if( $ArgumentList )
                {
                    Write-Error -Message ('Can''t use ArgumentList parameter with Command parameter because powershell.exe''s -Command parameter doesn''t support it. Please embed the argument list in your command string, or convert your command to a script block and use the `ScriptBlock` parameter.')
                    return
                }
    
                $argName = '-Command'
                if( $Encode )
                {
                    $Command = ConvertTo-Base64 -Value $Command
                    $argName = '-EncodedCommand'
                }
                if( $Credential )
                {
                    Start-PowerShellProcess -CommandLine ('{0} {1} {2}' -f ($powerShellArgs -join " "),$argName,$Command) -Credential $Credential
                }
                else
                {
                    Write-Debug ('{0} {1} {2} {3}' -f $psPath,($powerShellArgs -join " "),$argName,$Command)
                    & $psPath $powerShellArgs $argName $Command
                    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
                }
            }
        }
    }
    
    
  • Carbon\Functions\Join-IisVirtualPath.ps1 Show
    # 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('/')
    }
    
    
  • Carbon\Functions\Lock-IisConfigurationSection.ps1 Show
    # 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()
                }
            }
    }
    
    
  • Carbon\Functions\New-Credential.ps1 Show
    # 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
        {
        }
    }
    
    
  • Carbon\Functions\New-Junction.ps1 Show
    # 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 
            } 
        }
    }
    
    
  • Carbon\Functions\New-RsaKeyPair.ps1 Show
    # 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
        }
    }
    
  • Carbon\Functions\New-TempDirectory.ps1 Show
    # 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'
    
  • Carbon\Functions\Protect-String.ps1 Show
    # 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
        The `Protect-String` function encrypts a string using the Data Protection API (DPAPI), RSA, or AES. In Carbon 2.3.0 or earlier, the plaintext string to encrypt is passed to the `String` parameter. Beginning in Carbon 2.4.0, you can also pass a `SecureString`. When encrypting a `SecureString`, it is converted to an array of bytes, encrypted, then the array of bytes is cleared from memory (i.e. the plaintext version of the `SecureString` is only in memory long enough to encrypt it).
        
        ##  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). `Protect-String` encrypts with .NET's `System.Security.Cryptography.RSACryptoServiceProvider` class.
    
        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
    
        You can generate an RSA public/private key pair with the `New-RsaKeyPair` function.
    
        ## AES
    
        AES is a symmetric encryption/decryption algorithm. You supply a 16-, 24-, or 32-byte key/password/passphrase with the `Key` parameter, and that key is used to encrypt. There is no limit on the size of the data you want to encrypt. `Protect-String` encrypts with .NET's `System.Security.Cryptography.AesCryptoServiceProvider` class.
    
        Symmetric encryption requires a random, unique initialization vector (i.e. IV) everytime you encrypt something. `Protect-String` generates one for you. This IV must be known to decrypt the secret, so it is pre-pendeded to the encrypted text.
    
        This code demonstrates how to generate a key:
    
            $key = (New-Object 'Security.Cryptography.AesManaged').Key
    
        You can save this key as a string by encoding it as a base-64 string:
    
            $base64EncodedKey = [Convert]::ToBase64String($key)
    
        If you base-64 encode your string, it must be converted back to bytes before passing it to `Protect-String`.
    
            Protect-String -String 'the secret sauce' -Key ([Convert]::FromBase64String($base64EncodedKey))
    
        The ability to encrypt with AES was added in Carbon 2.3.0.
       
        .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
        Protect-String -String $credential.Password -ForUser | Out-File MySecret.txt
    
        Demonstrates that `Protect-String` can encrypt a `SecureString`. This functionality was added in Carbon 2.4.0. 
        
        .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
        Protect-String -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
        Protect-String -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.
    
        .EXAMPLE
        Protect-String -String 'the secret sauce' -Key 'gT4XPfvcJmHkQ5tYjY3fNgi7uwG4FB9j'
    
        Demonstrates how to encrypt a secret with a key, password, or passphrase. In this case, we are encrypting with a plaintext password. This functionality was added in Carbon 2.3.0.
    
        .EXAMPLE
        Protect-String -String 'the secret sauce' -Key (Read-Host -Prompt 'Enter password (must be 16, 24, or 32 characters long):' -AsSecureString)
    
        Demonstrates that you can use a `SecureString` as the key, password, or passphrase. This functionality was added in Carbon 2.3.0.
    
        .EXAMPLE
        Protect-String -String 'the secret sauce' -Key ([byte[]]@(163,163,185,174,205,55,157,219,121,146,251,116,43,203,63,38,73,154,230,112,82,112,151,29,189,135,254,187,164,104,45,30))
    
        Demonstrates that you can use an array of bytes as the key, password, or passphrase. This functionality was added in Carbon 2.3.0.
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory = $true, Position=0, ValueFromPipeline = $true)]
            [object]
            # The string to encrypt. Any non-string object you pass will be converted to a string before encrypting by calling the object's `ToString` method.
            #
            # Beginning in Carbon 2.4.0, this can also be a `SecureString` object. The `SecureString` is converted to an array of bytes, the bytes are encrypted, then the plaintext bytes are cleared from memory (i.e. the plaintext password is in memory for the amount of time it takes to encrypt it).
            $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,
    
            [Parameter(Mandatory=$true,ParameterSetName='Symmetric')]
            # The key to use to encrypt the secret. Can be a `SecureString`, a `String`, or an array of bytes. Must be 16, 24, or 32 characters/bytes in length.
            [object]
            $Key
        )
        
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        if( $String -is [System.Security.SecureString] )
        {
            $stringBytes = [Carbon.Security.SecureStringConverter]::ToBytes($String)   
        }
        else
        {
            $stringBytes = [Text.Encoding]::UTF8.GetBytes( $String.ToString() )
        }
        
        try
        {    
    
            if( $PSCmdlet.ParameterSetName -like 'DPAPI*' )
            {
                if( $PSCmdlet.ParameterSetName -eq 'DPAPIForUser' ) 
                {
                    $protectStringPath = Join-Path -Path $CarbonBinDir -ChildPath 'Protect-String.ps1' -Resolve
                    $encodedString = Protect-String -String $String -ForComputer
                    $argumentList = '-ProtectedString {0}' -f $encodedString
                    Invoke-PowerShell -ExecutionPolicy 'ByPass' -NonInteractive -FilePath $protectStringPath -ArgumentList $argumentList -Credential $Credential |
                        Select-Object -First 1
                    return
                }
                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
                    }
                }
    
                $rsaKey = $Certificate.PublicKey.Key
                if( $rsaKey -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,$rsaKey.GetType().FullName,[Security.Cryptography.RSACryptoServiceProvider].FullName)
                    return
                }
    
                try
                {
                    $encryptedBytes = $rsaKey.Encrypt( $stringBytes, (-not $UseDirectEncryptionPadding) )
                }
                catch
                {
                    if( $_.Exception.Message -match 'Bad Length\.' -or $_.Exception.Message -match 'The parameter is incorrect\.')
                    {
                        [int]$maxLengthGuess = ($rsaKey.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 $rsaKey.KeySize,$Certificate.Subject,$Certificate.Thumbprint,$maxLengthGuess)
                        return
                    }
                    else
                    {
                        Write-Error -Exception $_.Exception
                        return
                    }
                }
            }
            elseif( $PSCmdlet.ParameterSetName -eq 'Symmetric' )
            {
                $Key = ConvertTo-Key -InputObject $Key -From 'Protect-String'
                if( -not $Key )
                {
                    return
                }
                    
                $aes = New-Object 'Security.Cryptography.AesCryptoServiceProvider'
                try
                {
                    $aes.Padding = [Security.Cryptography.PaddingMode]::PKCS7
                    $aes.KeySize = $Key.Length * 8
                    $aes.Key = $Key
    
                    $memoryStream = New-Object 'IO.MemoryStream'
                    try
                    {
                        $cryptoStream = New-Object 'Security.Cryptography.CryptoStream' $memoryStream,$aes.CreateEncryptor(),([Security.Cryptography.CryptoStreamMode]::Write)
                        try
                        {
                            $cryptoStream.Write($stringBytes,0,$stringBytes.Length)
                        }
                        finally
                        {
                            $cryptoStream.Dispose()
                        }
    
                        $encryptedBytes = Invoke-Command -ScriptBlock {
                                                                         $aes.IV
                                                                         $memoryStream.ToArray()
                                                                      }
                    }
                    finally
                    {
                        $memoryStream.Dispose()
                    }
                }
                finally
                {
                    $aes.Dispose()
                }
            }
    
            return [Convert]::ToBase64String( $encryptedBytes )
        }
        finally
        {
            $stringBytes.Clear()
        }
    }
    
    
  • Carbon\Functions\Read-File.ps1 Show
    # 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 = @{}
            }
    
            $cmdErrors = @()
            $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 $Global:Error is full, $numErrors will be 0
            if( $cmdErrors -or $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 )
    }
  • Carbon\Functions\Remove-DotNetAppSetting.ps1 Show
    # 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
            }
        }
    }
    
    
  • Carbon\Functions\Remove-EnvironmentVariable.ps1 Show
    # 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.
    
        Normally, you have to restart your PowerShell session/process to no longer see the variable in the `env:` drive. Use the `-Force` switch to also remove the variable from the `env:` drive. This functionality was added in Carbon 2.3.0.
    
        Beginning with Carbon 2.3.0, you can set an environment variable for a specific user by specifying the `-ForUser` switch and passing the user's credentials with the `-Credential` parameter. This runs a separate PowerShell process as that user to remove the variable.
    
        Beginning in Carbon 2.3.0, you can specify multiple scopes from which to remove an environment variable. In previous versions, you could only remove from one scope.
        
        .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.
    
        .EXAMPLE
        Remove-EnvironmentVariable -Name 'SomeUsersVariable' -ForUser -Credential $credential
    
        Demonstrates that you can remove another user's user-level environment variable by passing its credentials to the `Credential` parameter. This runs a separate PowerShell process as that user to remove the variable.
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The environment variable to remove.
            $Name,
            
            [Parameter(ParameterSetName='ForCurrentUser')]
            [Switch]
            # Removes the environment variable for the current computer.
            $ForComputer,
    
            [Parameter(ParameterSetName='ForCurrentUser')]
            [Parameter(Mandatory=$true,ParameterSetName='ForSpecificUser')]
            [Switch]
            # Removes the environment variable for the current user.
            $ForUser,
            
            [Parameter(ParameterSetName='ForCurrentUser')]
            [Switch]
            # Removes the environment variable for the current process.
            $ForProcess,
    
            [Parameter(ParameterSetName='ForCurrentUser')]
            [Switch]
            # Remove the variable from the current PowerShell session's `env:` drive, too. Normally, you have to restart your session to no longer see the variable in the `env:` drive.
            #
            # This parameter was added in Carbon 2.3.0.
            $Force,
    
            [Parameter(Mandatory=$true,ParameterSetName='ForSpecificUser')]
            [pscredential]
            # Remove an environment variable for a specific user.
            $Credential
        )
        
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        if( $PSCmdlet.ParameterSetName -eq 'ForSpecificUser' )
        {
            Invoke-PowerShell -FilePath (Join-Path -Path $PSScriptRoot -ChildPath '..\bin\Remove-EnvironmentVariable.ps1' -Resolve) `
                              -Credential $credential `
                              -ArgumentList ('-Name {0}' -f (ConvertTo-Base64 $Name)) `
                              -NonInteractive `
                              -OutputFormat 'text'
            return
        }
    
        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
                                        }
                                    } |
            Where-Object { $PSCmdlet.ShouldProcess( "$_-level environment variable '$Name'", "remove" ) } |
            ForEach-Object { 
                                $scope = $_
                                [Environment]::SetEnvironmentVariable( $Name, $null, $scope )
                                if( $Force -and $scope -ne [EnvironmentVariableTarget]::Process )
                                {
                                    [Environment]::SetEnvironmentVariable($Name, $null, 'Process')
                                }
                }
    }
    
    
  • Carbon\Functions\Remove-GroupMember.ps1 Show
    # 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()
        }
    }
    
    
  • Carbon\Functions\Remove-HostsEntry.ps1 Show
    # 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
            }
        }
    }
    
  • Carbon\Functions\Remove-IisMimeMap.ps1 Show
    # 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()
    }
    
    
  • Carbon\Functions\Remove-IniEntry.ps1 Show
    # 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
                }
            }
        }
    
    }
    
  • Carbon\Functions\Remove-Junction.ps1 Show
    # 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)
        }
    }
    
    
  • Carbon\Functions\Remove-RegistryKeyValue.ps1 Show
    # 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
            }
        }
    }
    
    
  • Carbon\Functions\Remove-SslCertificateBinding.ps1 Show
    # 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 }
    }
    
    
  • Carbon\Functions\Reset-HostsFile.ps1 Show
    # 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
        }     
    }
    
    
  • Carbon\Functions\Reset-MsmqQueueManagerID.ps1 Show
    # 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"
    }
    
    
  • Carbon\Functions\Resolve-FullPath.ps1 Show
    # 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'
    
    
  • Carbon\Functions\Resolve-Identity.ps1 Show
    # 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 ) 
    }
    
    
  • Carbon\Functions\Resolve-IdentityName.ps1 Show
    # 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()
            }
        }
        
    }
    
    
  • Carbon\Functions\Resolve-NetPath.ps1 Show
    # 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
    }
    
  • Carbon\Functions\Resolve-PathCase.ps1 Show
    # 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'
    
    
  • Carbon\Functions\Resolve-RelativePath.ps1 Show
    # 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
        }
    }
    
  • Carbon\Functions\Resolve-WindowsFeatureName.ps1 Show
    # 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[$_] }
    
    }
    
    
  • Carbon\Functions\Restart-RemoteService.ps1 Show
    # 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"
        }  
    }
     
    
  • Carbon\Functions\Revoke-ComPermission.ps1 Show
    # 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-ComPermission
    {
        <#
        .SYNOPSIS
        Revokes COM Access or Launch and Activation permissions.
        
        .DESCRIPTION
        Calling this function is equivalent to opening Component Services (dcomcnfg), right-clicking `My Computer` under Component Services > Computers, choosing `Properties`, going to the `COM Security` tab, and removing an identity from the permissions window that opens after clicking the `Edit Limits...` or `Edit Default...` buttons under `Access Permissions` or `Launch and Activation Permissions` section, 
        
        .LINK
        Get-ComPermission
    
        .LINK
        Grant-ComPermission
        
        .LINK
        Revoke-ComPermission
        
        .EXAMPLE
        Revoke-ComPermission -Access -Identity 'Users' -Default
        
        Removes all default security COM access permissions for the local `Users` group.
    
        .EXAMPLE
        Revoke-ComPermission -LaunchAndActivation -Identity 'Users' -Limits
        
        Removes all security limit COM access permissions for the local `Users` group.
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [string]        
            $Identity,
            
            [Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermission')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestriction')]
            [Switch]
            # Revokes Access Permissions.
            $Access,
            
            [Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermission')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestriction')]
            [Switch]
            # Revokes Launch and Activation Permissions.
            $LaunchAndActivation,
            
            [Parameter(Mandatory=$true,ParameterSetName='DefaultAccessPermission')]
            [Parameter(Mandatory=$true,ParameterSetName='DefaultLaunchPermission')]
            [Switch]
            # Revokes default security permissions.
            $Default,
            
            [Parameter(Mandatory=$true,ParameterSetName='MachineAccessRestriction')]
            [Parameter(Mandatory=$true,ParameterSetName='MachineLaunchRestriction')]
            [Switch]
            # Revokes security limits permissions.
            $Limits
        )
        
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $comArgs = @{ }
        if( $pscmdlet.ParameterSetName -like 'Default*' )
        {
            $typeDesc = 'default security permissions'
            $comArgs.Default = $true
        }
        else
        {
            $typeDesc = 'security limits'
            $comArgs.Limits = $true
        }
        
        if( $pscmdlet.ParameterSetName -like '*Access*' )
        {
            $permissionsDesc = 'Access'
            $comArgs.Access = $true
        }
        else
        {
            $permissionsDesc = 'Launch and Activiation'
            $comArgs.LaunchAndActivation = $true
        }
        
        $account = Resolve-Identity -Name $Identity
        if( -not $account )
        {
            return
        }
    
        Write-Verbose ("Revoking {0}'s COM {1} {2}." -f $Identity,$permissionsDesc,$typeDesc)
        $currentSD = Get-ComSecurityDescriptor @comArgs
    
        $newSd = ([wmiclass]'win32_securitydescriptor').CreateInstance()
        $newSd.ControlFlags = $currentSD.ControlFlags
        $newSd.Group = $currentSD.Group
        $newSd.Owner = $currentSD.Owner
    
        # Remove DACL for this user, if it exists
        $newSd.DACL = $currentSD.DACL | 
                        Where-Object { $_.Trustee.SIDString -ne $account.Sid.Value } | 
                        ForEach-Object { $_.PsObject.BaseObject }
    
        $converter = New-Object Management.ManagementClass 'Win32_SecurityDescriptorHelper'
        $sdBytes = $converter.Win32SDToBinarySD( $newSd )
    
        $regValueName = $pscmdlet.ParameterSetName
        Set-RegistryKeyValue -Path $ComRegKeyPath -Name $regValueName -Binary $sdBytes.BinarySD -Quiet
    }
    
    Set-Alias -Name 'Revoke-ComPermissions' -Value 'Revoke-ComPermission'
    
    
  • Carbon\Functions\Revoke-HttpUrlPermission.ps1 Show
    # 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-HttpUrlPermission
    {
        <#
        .SYNOPSIS
        Revokes all a principal's permission to an HTTP URL.
    
        .DESCRIPTION
        The `Revoke-HttpUrlAclPermission` functions uses the HTTP Server API to revoke user/groups permissions to an HTTP URL.
    
        [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. This function removes all permissions to a URL for a specific user or group. If a user or group doesn't have permission, this function does nothing.
    
        If you want to *change* a user's permissions, use `Grant-HttpUrlPermission` instead.
    
        This command replaces the `netsh http delete urlacl` command.
    
        `Revoke-HttpUrlAclPermission` was introduced in Carbon 2.1.0.
    
        .LINK
        https://msdn.microsoft.com/en-us/library/aa364510.aspx
    
        .LINK
        Get-HttpUrlAcl
    
        .LINK
        Grant-HttpUrlPermission
    
        .EXAMPLE
        Revoke-HttpUrlAclPermission -Url 'http://+:4833' -Principal 'FALCON\HSolo'
    
        Demonstrates how to revoke all a user's permissions to an HTTP URL. In this case Captain Solo will no longer be able to listen to URL `http://+:4833`.
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The URL.
            $Url,
    
            [Parameter(Mandatory=$true)]
            [Alias('Identity')]
            [string]
            # The user receiving the permission.
            $Principal
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $id = Resolve-Identity -Name $Principal
        if( -not $id )
        {
            return
        }
    
        if( -not $Url.EndsWith('/') )
        {
            $Url = '{0}/' -f $Url
        }
    
        $acl = Get-HttpUrlAcl -LiteralUrl $Url -ErrorAction Ignore
        if( -not $acl )
        {
            return
        }
    
        $currentAccess = $acl.Access | Where-Object { $_.IdentityReference -eq $id.FullName }
        if( $currentAccess )
        {
            Write-Verbose -Message ('[{0}]  [{1}]  {2} ->' -f $Url,$id.FullName,$currentAccess.HttpUrlAccessRights)
            $acl.RemoveAccessRule($currentAccess)
        }
    }
  • Carbon\Functions\Revoke-Permission.ps1 Show
    # 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-Permission
    {
        <#
        .SYNOPSIS
        Revokes *explicit* permissions on a file, directory, registry key, or certificate's private key/key container.
    
        .DESCRIPTION
        Revokes all of an identity's *explicit* permissions on a file, directory, registry key, or certificate's private key/key container. Only explicit permissions are considered; inherited permissions are ignored.
    
        If the identity doesn't have permission, nothing happens, not even errors written out.
    
        .LINK
        Carbon_Permission
    
        .LINK
        Disable-AclInheritance
    
        .LINK
        Enable-AclInheritance
    
        .LINK
        Get-Permission
    
        .LINK
        Grant-Permission
    
        .LINK
        Test-Permission
    
        .EXAMPLE
        Revoke-Permission -Identity ENTERPRISE\Engineers -Path 'C:\EngineRoom'
    
        Demonstrates how to revoke all of the 'Engineers' permissions on the `C:\EngineRoom` directory.
    
        .EXAMPLE
        Revoke-Permission -Identity ENTERPRISE\Interns -Path 'hklm:\system\WarpDrive'
    
        Demonstrates how to revoke permission on a registry key.
    
        .EXAMPLE
        Revoke-Permission -Identity ENTERPRISE\Officers -Path 'cert:\LocalMachine\My\1234567890ABCDEF1234567890ABCDEF12345678'
    
        Demonstrates how to revoke the Officers' permission to the `cert:\LocalMachine\My\1234567890ABCDEF1234567890ABCDEF12345678` certificate's private key/key container.
        #>
        [CmdletBinding(SupportsShouldProcess=$true)]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The path on which the permissions should be revoked.  Can be a file system, registry, or certificate path.
            $Path,
            
            [Parameter(Mandatory=$true)]
            [string]
            # The identity losing permissions.
            $Identity
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
        
        $Path = Resolve-Path -Path $Path
        if( -not $Path )
        {
            return
        }
    
        $providerName = Get-PathProvider -Path $Path | Select-Object -ExpandProperty 'Name'
        if( $providerName -eq 'Certificate' )
        {
            $providerName = 'CryptoKey'
        }
    
        $rulesToRemove = Get-Permission -Path $Path -Identity $Identity
        if( $rulesToRemove )
        {
            $Identity = Resolve-IdentityName -Name $Identity
            $rulesToRemove | ForEach-Object { Write-Verbose ('[{0}] [{1}]  {2} -> ' -f $Path,$Identity,$_."$($providerName)Rights") }
    
            Get-Item $Path -Force |
                ForEach-Object {
                    if( $_.PSProvider.Name -eq 'Certificate' )
                    {
                        [Security.Cryptography.X509Certificates.X509Certificate2]$certificate = $_
    
                        [Security.AccessControl.CryptoKeySecurity]$keySecurity = $certificate.PrivateKey.CspKeyContainerInfo.CryptoKeySecurity
    
                        $rulesToRemove | ForEach-Object { [void] $keySecurity.RemoveAccessRule($_) }
    
                        Set-CryptoKeySecurity -Certificate $certificate -CryptoKeySecurity $keySecurity -Action ('revoke {0}''s permissions' -f $Identity)
                    }
                    else
                    {
                        # We don't use Get-Acl because it returns the whole security descriptor, which includes owner information.
                        # When passed to Set-Acl, this causes intermittent errors.  So, we just grab the ACL portion of the security descriptor.
                        # See http://www.bilalaslam.com/2010/12/14/powershell-workaround-for-the-security-identifier-is-not-allowed-to-be-the-owner-of-this-object-with-set-acl/
                        $currentAcl = $_.GetAccessControl('Access')
                        $rulesToRemove | ForEach-Object { [void]$currentAcl.RemoveAccessRule($_) }
                        if( $PSCmdlet.ShouldProcess( $Path, ('revoke {0}''s permissions' -f $Identity)) )
                        {
                            Set-Acl -Path $Path -AclObject $currentAcl
                        }
                    }
                }
    
        }
        
    }
    
    
  • Carbon\Functions\Revoke-Privilege.ps1 Show
    # 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
            }
        }
    }
    
    
  • Carbon\Functions\Revoke-ServicePermission.ps1 Show
    # 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-ServicePermission
    {
        <#
        .SYNOPSIS
        Removes all permissions an identity has to manage a service.
        
        .DESCRIPTION
        No permissions are left behind.  This is an all or nothing operation, baby!
        
        .LINK
        Get-ServicePermission
        
        .LINK
        Grant-ServicePermission
        
        .EXAMPLE
        Revoke-ServicePermission -Name 'Hyperdrive` -Identity 'CLOUDCITY\LCalrissian'
        
        Removes all of Lando's permissions to control the `Hyperdrive` service.
        #>
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [string]
            # The service.
            $Name,
            
            [Parameter(Mandatory=$true)]
            [string]
            # The identity whose permissions are being revoked.
            $Identity
        )
        
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        $account = Resolve-Identity -Name $Identity
        if( -not $account )
        {
            return
        }
        
        if( -not (Assert-Service -Name $Name) )
        {
            return
        }
        
        if( (Get-ServicePermission -Name $Name -Identity $account.FullName) )
        {
            Write-Verbose ("Revoking {0}'s {1} service permissions." -f $account.FullName,$Name)
            
            $dacl = Get-ServiceAcl -Name $Name
            $dacl.Purge( $account.Sid )
            
            Set-ServiceAcl -Name $Name -Dacl $dacl
        }
     }
     
    
  • Carbon\Functions\Set-CryptoKeySecurity.ps1 Show
    # 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)
        }
    }
    
  • Carbon\Functions\Set-DotNetAppSetting.ps1 Show
    # 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
            }
        }
    }
    
    
  • Carbon\Functions\Set-DotNetConnectionString.ps1 Show
    # 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
            }
        }
    }
    
    
  • Carbon\Functions\Set-EnvironmentVariable.ps1 Show
    # 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.
    
        Beginning with Carbon 2.3.0, you can set an environment variable for a specific user by specifying the `-ForUser` switch and passing the user's credentials with the `-Credential` parameter. This will run a PowerShell process as that user in order to set the environment variable.
    
        Normally, you have to restart your PowerShell session/process to see the variable in the `env:` drive. Use the `-Force` switch to also add the variable to the `env:` drive. This functionality was added in Carbon 2.3.0.
        
        .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.
        
        .EXAMPLE
        Set-EnvironmentVariable -Name 'SomeUsersEnvironmentVariable' -Value 'SomeValue' -ForUser -Credential $userCreds
    
        Demonstrates that you can set a user-level environment variable for another user by passing its credentials to the `Credential` parameter. Runs a separate PowerShell process as that user to set the environment variable.
        #>
        [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,
            
            [Parameter(ParameterSetName='ForCurrentUser')]
            # Sets the environment variable for the current computer.
            [Switch]
            $ForComputer,
    
            [Parameter(ParameterSetName='ForCurrentUser')]
            [Parameter(Mandatory=$true,ParameterSetName='ForSpecificUser')]
            # Sets the environment variable for the current user.
            [Switch]
            $ForUser,
            
            [Parameter(ParameterSetName='ForCurrentUser')]
            # Sets the environment variable for the current process.
            [Switch]
            $ForProcess,
    
            [Parameter(ParameterSetName='ForCurrentUser')]
            [Switch]
            # Set the variable in the current PowerShell session's `env:` drive, too. Normally, you have to restart your session to see the variable in the `env:` drive.
            #
            # This parameter was added in Carbon 2.3.0.
            $Force,
    
            [Parameter(Mandatory=$true,ParameterSetName='ForSpecificUser')]
            [pscredential]
            # Set an environment variable for a specific user.
            $Credential
        )
    
        Set-StrictMode -Version 'Latest'
    
        Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState
    
        if( $PSCmdlet.ParameterSetName -eq 'ForSpecificUser' )
        {
            Invoke-PowerShell -FilePath (Join-Path -Path $PSScriptRoot -ChildPath '..\bin\Set-EnvironmentVariable.ps1' -Resolve) `
                              -Credential $credential `
                              -ArgumentList ('-Name {0} -Value {1}' -f (ConvertTo-Base64 $Name),(ConvertTo-Base64 $Value)) `
                              -NonInteractive `
                              -OutputFormat 'text'
            return
        }
    
        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( $Force -or $ForProcess )
                {
                    [EnvironmentVariableTarget]::Process
                }
            } | 
            Where-Object { $PSCmdlet.ShouldProcess( "$_-level environment variable '$Name'", "set") } |
            ForEach-Object { [Environment]::SetEnvironmentVariable( $Name, $Value, $_ ) }    
    }
    
    
  • Carbon\Functions\Set-HostsEntry.ps1 Show
    # 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,-45}  {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,-45}  {2}' -f $Path,$IPAddress,$HostName)
        $outLines | Write-File -Path $Path
    }
    
    
  • Carbon\Functions\Set-IisHttpHeader.ps1 Show
    # 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()
        }
    }
    
    
  • Carbon\Functions\Set-IisHttpRedirect.ps1 Show
    # 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()
        }
    }
    
    
  • Carbon\Functions\Set-IisMimeMap.ps1 Show
    # 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()
        }
    }
    
    
  • Carbon\Functions\Set-IisWebsiteID.ps1 Show
    # 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)
        }
    }
    
    
  • Carbon\Functions\Set-IisWebsiteSslCertificate.ps1 Show
    # 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
        }
    }
    
    
  • Carbon\Functions\Set-IisWindowsAuthentication.ps1 Show
    # 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()
        }
    }
    
    
    
  • Carbon\Functions\Set-IniEntry.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Set-RegistryKeyValue.ps1 Show
    # 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')]
            [AllowEmptyString()]
            [AllowNull()]
            [string]
            # The value's data.  Creates a value for holding string data (i.e. `REG_SZ`). If `$null`, the value will be saved as an empty string.
            $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
        }
    }
    
    
  • Carbon\Functions\Set-ServiceAcl.ps1 Show
    # 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 )
        }
    }
    
    
  • Carbon\Functions\Set-SslCertificateBinding.ps1 Show
    # 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
            }
        }
    }
    
    
  • Carbon\Functions\Set-TrustedHost.ps1 Show
    # 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'
    
    
  • Carbon\Functions\Split-Ini.ps1 Show
    # 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
            }
        }
    }
    
    
  • Carbon\Functions\Start-DscPullConfiguration.ps1 Show
    # 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
    }
    
    
  • Carbon\Functions\Start-PowerShellProcess.ps1 Show
    # 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