├── .gitignore ├── LICENSE.txt ├── README.md └── src ├── IISManager.psd1 ├── IISManager.psm1 ├── Private ├── Converters.ps1 ├── Helpers.ps1 └── Paths.ps1 └── Public ├── AppPools.ps1 ├── Apps.ps1 ├── Directories.ps1 ├── Ftp.ps1 ├── Logging.ps1 ├── Misc.ps1 └── Sites.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | notes.txt -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) [2019] [Matthew Kelly (Badgerati)] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IISManager 2 | 3 | [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/Badgerati/IISManager/master/LICENSE.txt) 4 | [![PowerShell](https://img.shields.io/powershellgallery/dt/iismanager.svg?label=PowerShell&colorB=085298)](https://www.powershellgallery.com/packages/IISManager) 5 | 6 | This is a lightweight PowerShell module to help manage IIS instances, with support for working in PowerShell Core on Windows (including the Ubuntu prompt on Windows). 7 | 8 | Unlike other modules, this module has no dependency on any DLLs. The only dependency is that you have IIS installed on the server (or your machine). 9 | 10 | There is also support for binding certificates to websites, and sharing directories. 11 | 12 | Feel free to contribute. 13 | 14 | ## Install 15 | 16 | ```powershell 17 | Install-Module -Name IISManager 18 | Import-Module -Name IISManager 19 | ``` 20 | 21 | ## Functions 22 | 23 | ### Application Pools 24 | 25 | * Get-IISMAppPool 26 | * Get-IISMAppPools 27 | * New-IISMAppPool 28 | * Remove-IISMAppPool 29 | * Reset-IISMAppPool 30 | * Restart-IISMAppPool 31 | * Start-IISMAppPool 32 | * Stop-IISMAppPool 33 | * Test-IISMAppPool 34 | * Test-IISMAppPoolRunning 35 | * Update-IISMAppPool 36 | * Update-IISMAppPoolProcessModel 37 | * Update-IISMAppPoolRecycling 38 | 39 | ### Apps 40 | 41 | * Get-IISMApp 42 | * New-IISMApp 43 | * Remove-IISMApp 44 | * Test-IISMApp 45 | * Update-IISMApp 46 | 47 | ### Directories 48 | 49 | * Get-IISMDirectory 50 | * Get-IISMDirectoryShare 51 | * Mount-IISMDirectoryShare 52 | * New-IISMDirectory 53 | * Remove-IISMDirectory 54 | * Remove-IISMDirectoryShare 55 | * Set-IISMDirectoryCredentials 56 | * Test-IISMDirectory 57 | * Test-IISMDirectoryShare 58 | * Update-IISMDirectory 59 | * Update-IISMDirectoryPhysicalPaths 60 | 61 | ### Sites 62 | 63 | * Add-IISMSiteBinding 64 | * Edit-IISMSiteAppPool 65 | * Edit-IISMSitePhysicalPath 66 | * Get-IISMSiteAppPool 67 | * Get-IISMSiteBindingCertificate 68 | * Get-IISMSiteBindings 69 | * Get-IISMSitePhysicalPath 70 | * Get-IISMSite 71 | * Get-IISMSites 72 | * New-IISMSite 73 | * Remove-IISMSite 74 | * Remove-IISMSiteBinding 75 | * Remove-IISMSiteBindings 76 | * Remove-IISMSiteDefaultBinding 77 | * Remove-IISMSiteBindingCertificate 78 | * Reset-IISMSiteAppPool 79 | * Restart-IISMSite 80 | * Set-IISMSiteBindingCertificate 81 | * Start-IISMSite 82 | * Stop-IISMSite 83 | * Test-IISMSite 84 | * Test-IISMSiteBinding 85 | * Test-IISMSiteBindingCertificate 86 | * Test-IISMSiteRunning 87 | 88 | ### Logging 89 | 90 | * Add-IISMSiteCustomLogField 91 | * Add-IISMSiteLogField 92 | * Clear-IISMSiteCustomLogFields 93 | * Clear-IISMSiteLogFields 94 | * Get-IISMSiteCustomLogFields 95 | * Get-IISMSiteLogFields 96 | * Get-IISMSiteLogFormat 97 | * Get-IISMSiteLogging 98 | * Get-IISMSiteLogPath 99 | * Get-IISMSiteLogPeriod 100 | * Remove-IISMSiteCustomLogField 101 | * Remove-IISMSiteLogField 102 | * Set-IISMSiteLogFields 103 | * Set-IISMSiteLogPath 104 | * Set-IISMSiteLogPeriod 105 | * Test-IISMSiteCustomLogField 106 | * Test-IISMSiteLogField 107 | 108 | 109 | ### FTP 110 | 111 | * Add-IISMFtpDirectoryIPSecurity 112 | * Add-IISMFtpDirectoryAuthorization 113 | * Add-IISMFtpServerCustomAuthentication 114 | * Add-IISMFtpSiteCustomAuthentication 115 | * Add-IISMFtpSiteLogField 116 | * Clear-IISMFtpSiteLogFields 117 | * Disable-IISMFtpSiteAuthentication 118 | * Enable-IISMFtpSiteAuthentication 119 | * Get-IISMFtpDirectoryAuthorization 120 | * Get-IISMFtpDirectoryIPSecurity 121 | * Get-IISMFtpServerCustomAuthentication 122 | * Get-IISMFtpServerCustomAuthenticationProvider 123 | * Get-IISMFtpSiteLogging 124 | * Get-IISMFtpSiteLogFields 125 | * Get-IISMFtpSiteLogPath 126 | * Get-IISMFtpSiteLogPeriod 127 | * Register-IISMFtpServerCustomAuthenticationProvider 128 | * Remove-IISMFtpDirectoryAuthorization 129 | * Remove-IISMFtpDirectoryIPSecurity 130 | * Remove-IISMFtpServerCustomAuthentication 131 | * Remove-IISMFtpSiteCustomAuthentication 132 | * Remove-IISMFtpSiteLogField 133 | * Set-IISMFtpDirectoryIPSecurityUnlisted 134 | * Set-IISMFtpSiteLogFields 135 | * Set-IISMFtpSiteLogPath 136 | * Set-IISMFtpSiteLogPeriod 137 | * Set-IISMFtpSiteSslPolicy 138 | * Set-IISMFtpSiteUserIsolation 139 | * Test-IISMFtpSiteLogField 140 | * Test-IISMSiteIsFtp 141 | * Unregister-IISMFtpServerCustomAuthenticationProvider 142 | 143 | ### Misc 144 | 145 | * Get-IISMCertificateThumbprint 146 | * Invoke-IISMAppCommand 147 | * New-IISMCredentials 148 | * Reset-IISMServer 149 | 150 | ## ToDo 151 | 152 | * Hosts file control 153 | * Folder permissions via ACL 154 | -------------------------------------------------------------------------------- /src/IISManager.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'IISManager' 3 | # 4 | # Generated by: Matthew Kelly (Badgerati) 5 | # 6 | # Generated on: 03/06/2019 7 | # 8 | 9 | @{ 10 | # Script module or binary module file associated with this manifest. 11 | RootModule = 'IISManager.psm1' 12 | 13 | # Version number of this module. 14 | ModuleVersion = '2.1.1' 15 | 16 | # ID used to uniquely identify this module 17 | GUID = 'a3ba417c-dc1d-446b-95a5-a306ab26c1af' 18 | 19 | # Author of this module 20 | Author = 'Matthew Kelly (Badgerati)' 21 | 22 | # Copyright statement for this module 23 | Copyright = 'Copyright (c) 2019 Matthew Kelly (Badgerati), licensed under the MIT License.' 24 | 25 | # Description of the functionality provided by this module 26 | Description = 'PowerShell module to manage IIS, that also supports working in PowerShell Core' 27 | 28 | # Minimum version of the Windows PowerShell engine required by this module 29 | PowerShellVersion = '3.0' 30 | 31 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 32 | PrivateData = @{ 33 | PSData = @{ 34 | 35 | # Tags applied to this module. These help with module discovery in online galleries. 36 | Tags = @('powershell', 'web', 'server', 'websites', 'powershell-core', 'windows', 'PSEdition_Core', 37 | 'iis', 'management', 'administration', 'certificates', 'netsh', 'net', 'appcmd', 'ftp') 38 | 39 | # A URL to the license for this module. 40 | LicenseUri = 'https://raw.githubusercontent.com/Badgerati/IISManager/master/LICENSE.txt' 41 | 42 | # A URL to the main website for this project. 43 | ProjectUri = 'https://github.com/Badgerati/IISManager' 44 | 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/IISManager.psm1: -------------------------------------------------------------------------------- 1 | # load private functions 2 | $root = Split-Path -Parent -Path $MyInvocation.MyCommand.Path 3 | Get-ChildItem "$($root)/Private/*.ps1" | Resolve-Path | ForEach-Object { . $_ } 4 | 5 | 6 | # get existing functions from memory for later comparison 7 | $sysfuncs = Get-ChildItem Function: 8 | 9 | # load public functions 10 | Get-ChildItem "$($root)/Public/*.ps1" | Resolve-Path | ForEach-Object { . $_ } 11 | 12 | # get functions from memory and compare to existing to find new functions added 13 | $funcs = Get-ChildItem Function: | Where-Object { $sysfuncs -notcontains $_ } 14 | 15 | 16 | # export the module's public functions 17 | Export-ModuleMember -Function ($funcs.Name) -------------------------------------------------------------------------------- /src/Private/Converters.ps1: -------------------------------------------------------------------------------- 1 | function ConvertTo-IISMSiteObject 2 | { 3 | param ( 4 | [Parameter()] 5 | $Sites, 6 | 7 | [switch] 8 | $Quick 9 | ) 10 | 11 | if ($Quick) { 12 | return (ConvertTo-IISMSiteQuickObject -Sites $Sites) 13 | } 14 | 15 | $apps = Get-IISMApp 16 | $mapped = @() 17 | 18 | foreach ($site in $Sites) { 19 | # get app info 20 | $_apps = @(foreach ($app in $apps) { 21 | if (($null -ne $app) -and ($app.SiteName -ieq $site.site.name)) { 22 | $app 23 | } 24 | }) 25 | 26 | # get binding info 27 | $_bindings = @(ConvertTo-IISMBindingObject -Site $site) 28 | 29 | # get logging info 30 | $_logging = Get-IISMSiteLogging -Name $site.site.name 31 | 32 | # get the ftp info - but only if the protocol is ftp 33 | $_ftp = $null 34 | if ($_bindings.Protocol -icontains 'ftp') { 35 | $_ftp = ConvertTo-IISMFtpServerObject -SiteName $site.site.name -FtpServer $site.site.ftpServer 36 | } 37 | 38 | # server auto start 39 | $serverAutoStart = (($null -eq $site.site.serverAutoStart) -or ('true' -ieq $site.site.serverAutoStart)) 40 | 41 | # build site object 42 | $obj = @{ 43 | ID = $site.site.id 44 | Name = $site.site.name 45 | Bindings = @($_bindings) 46 | State = $site.state 47 | Apps = $_apps 48 | Limits = $null 49 | Logging = $_logging 50 | TraceFailedRequestsLogging = $null 51 | Hsts = $null 52 | ApplicationDefaults = $null 53 | Ftp = $_ftp 54 | ServerAutoStart = $serverAutoStart 55 | } 56 | 57 | $mapped += $obj 58 | } 59 | 60 | return $mapped 61 | } 62 | 63 | function ConvertTo-IISMBindingObject 64 | { 65 | param( 66 | [Parameter()] 67 | $Site 68 | ) 69 | 70 | if ($null -eq $Site) { 71 | return @() 72 | } 73 | 74 | return @(foreach ($binding in $Site.site.bindings.binding) { 75 | if ($null -ne $binding) { 76 | Get-IISMSiteBindingInformation -Binding $binding 77 | } 78 | }) 79 | } 80 | 81 | function ConvertTo-IISMSiteQuickObject 82 | { 83 | param ( 84 | [Parameter()] 85 | $Sites 86 | ) 87 | 88 | $mapped = @() 89 | 90 | foreach ($site in $Sites) { 91 | $obj = @{ 92 | ID = $site.site.id 93 | Name = $site.site.name 94 | Bindings = $null 95 | State = $site.state 96 | Apps = $null 97 | Limits = $null 98 | Logging = $null 99 | TraceFailedRequestsLogging = $null 100 | Hsts = $null 101 | ApplicationDefaults = $null 102 | Ftp = $null 103 | } 104 | 105 | $mapped += $obj 106 | } 107 | 108 | return $mapped 109 | } 110 | 111 | function ConvertTo-IISMSiteCustomLogFieldObject 112 | { 113 | param ( 114 | [Parameter()] 115 | $Fields 116 | ) 117 | 118 | $mapped = @() 119 | 120 | foreach ($field in $Fields) { 121 | $obj = @{ 122 | Name = $field.logFieldName 123 | Source = $field.sourceName 124 | Type = $field.sourceType 125 | } 126 | 127 | $mapped += $obj 128 | } 129 | 130 | return $mapped 131 | } 132 | 133 | function ConvertTo-IISMSiteLoggingObject 134 | { 135 | param ( 136 | [Parameter()] 137 | $Fields, 138 | 139 | [Parameter()] 140 | $CustomFields, 141 | 142 | [Parameter()] 143 | $Format, 144 | 145 | [Parameter()] 146 | $Path, 147 | 148 | [Parameter()] 149 | $Period 150 | ) 151 | 152 | $obj = @{ 153 | Fields = $Fields 154 | CustomFields = $CustomFields 155 | Format = $Format 156 | Path = $Path 157 | Period = $Period 158 | } 159 | 160 | return $obj 161 | } 162 | 163 | function ConvertTo-IISMFtpSiteLoggingObject 164 | { 165 | param ( 166 | [Parameter()] 167 | $Fields, 168 | 169 | [Parameter()] 170 | $Path, 171 | 172 | [Parameter()] 173 | $Period 174 | ) 175 | 176 | $obj = @{ 177 | Fields = $Fields 178 | Path = $Path 179 | Period = $Period 180 | } 181 | 182 | return $obj 183 | } 184 | 185 | function ConvertTo-IISMAppPoolObject 186 | { 187 | param ( 188 | [Parameter()] 189 | $AppPools 190 | ) 191 | 192 | $mapped = @() 193 | 194 | foreach ($pool in $AppPools) { 195 | $poolInfo = $pool.add 196 | 197 | $idleTimeout = '00:00:00' 198 | if (![string]::IsNullOrWhiteSpace($poolInfo.processModel.idleTimeout)) { 199 | $idleTimeout = $poolInfo.processModel.idleTimeout 200 | } 201 | 202 | $obj = @{ 203 | Name = $pool.'APPPOOL.NAME' 204 | PipelineMode = $pool.PipelineMode 205 | RuntimeVersion = $pool.RuntimeVersion 206 | State = $pool.state 207 | ProcessModel = @{ 208 | Credentials = (New-IISMCredentials -Username $poolInfo.processModel.userName -Password $poolInfo.processModel.password) 209 | IdentityType = $poolInfo.processModel.identityType 210 | MaxProcesses = [int]$poolInfo.processModel.maxProcesses 211 | IdleTimeout = @{ 212 | Duration = [timespan]$idleTimeout 213 | Action = $poolInfo.processModel.idleTimeoutAction 214 | } 215 | } 216 | Recycling = $null 217 | Failure = $null 218 | CPU = $null 219 | EnvironmentVariables = $null 220 | } 221 | 222 | $mapped += $obj 223 | } 224 | 225 | return $mapped 226 | } 227 | 228 | function ConvertTo-IISMAppObject 229 | { 230 | param ( 231 | [Parameter()] 232 | $Apps, 233 | 234 | [switch] 235 | $Quick 236 | ) 237 | 238 | $mapped = @() 239 | 240 | foreach ($app in $Apps) { 241 | if (!$Quick) { 242 | $_pool = Get-IISMAppPool -Name $app.'APPPOOL.NAME' 243 | $_info = Split-IISMAppName -AppName $app.'APP.NAME' 244 | $_dirs = Get-IISMDirectory -SiteName $_info.SiteName -AppName $_info.AppName 245 | } 246 | 247 | $obj = @{ 248 | Name = $app.'APP.NAME' 249 | Path = $app.path 250 | AppPool = $_pool 251 | SiteName = $app.'SITE.NAME' 252 | Directories = $_dirs 253 | } 254 | 255 | $mapped += $obj 256 | } 257 | 258 | return $mapped 259 | } 260 | 261 | function ConvertTo-IISMDirectoryObject 262 | { 263 | param( 264 | [Parameter()] 265 | $Directories, 266 | 267 | [switch] 268 | $Quick 269 | ) 270 | 271 | $mapped = @() 272 | 273 | foreach ($dir in $Directories) { 274 | # get the ftp info 275 | $_dirName = $dir.'VDIR.NAME' 276 | $_siteName = (Split-IISMDirectoryName -DirName $_dirName).SiteName 277 | 278 | if (!$Quick -and (Test-IISMSiteIsFtp -Name $_siteName)) { 279 | $_ftp = @{ 280 | Authorization = (Get-IISMFtpDirectoryAuthorizationInternal -Name $_dirName) 281 | IPSecurity = (Get-IISMFtpDirectoryIPSecurityInternal -Name $_dirName) 282 | } 283 | } 284 | 285 | # build the dir object 286 | $obj = @{ 287 | Name = $dir.'VDIR.NAME' 288 | PhysicalPath = $dir.physicalPath 289 | Path = $dir.path 290 | AppName = $dir.'APP.NAME' 291 | Credentials = (New-IISMCredentials -Username $dir.virtualDirectory.userName -Password $dir.virtualDirectory.password) 292 | Ftp = $_ftp 293 | } 294 | 295 | $mapped += $obj 296 | } 297 | 298 | return $mapped 299 | } 300 | 301 | function ConvertTo-IISMFtpServerObject 302 | { 303 | param( 304 | [Parameter(Mandatory=$true)] 305 | [string] 306 | $SiteName, 307 | 308 | [Parameter()] 309 | $FtpServer 310 | ) 311 | 312 | if ($null -eq $FtpServer) { 313 | return $null 314 | } 315 | 316 | $_security = ConvertTo-IISMFtpServerSecurityObject -Security $FtpServer.security 317 | 318 | return @{ 319 | Connections = $null 320 | Security = $_security 321 | CustomFeatures = @{ 322 | Providers = $null 323 | } 324 | Messages = $null 325 | FileHandling = $null 326 | FirewallSupport = $null 327 | UserIsolation = @{ 328 | Mode = Protect-IISMValue -Value1 $FtpServer.userIsolation.mode -Value2 'None' 329 | ActiveDirectory = @{ 330 | Credentials = (New-IISMCredentials -Username $FtpServer.userIsolation.activeDirectory.adUserName -Password $FtpServer.userIsolation.activeDirectory.adPassword) 331 | } 332 | } 333 | DirectoryBrowse = $null 334 | LogFile = (Get-IISMFtpSiteLogging -Name $SiteName) 335 | } 336 | } 337 | 338 | function ConvertTo-IISMFtpServerSecurityObject 339 | { 340 | param( 341 | [Parameter()] 342 | $Security 343 | ) 344 | 345 | if ($null -eq $Security) { 346 | return $null 347 | } 348 | 349 | # ftp ssl and cert 350 | $_ssl = @{ 351 | Certificate = (Get-IISMSiteBindingCertificate -Thumbprint $Security.ssl.serverCertHash) 352 | ControlChannelPolicy = $Security.ssl.controlChannelPolicy 353 | DataChannelPolicy = $Security.ssl.dataChannelPolicy 354 | } 355 | 356 | # ftp auth 357 | $_auth = @{ 358 | Anonymous = @{ 359 | Enabled = ($Security.authentication.anonymousAuthentication.enabled -ieq 'true') 360 | Credentials = (New-IISMCredentials -Username $Security.authentication.anonymousAuthentication.username -Password $Security.authentication.anonymousAuthentication.password) 361 | Domain = $Security.authentication.anonymousAuthentication.defaultLogonDomain 362 | LogonMethod = $Security.authentication.anonymousAuthentication.logonMethod 363 | } 364 | Basic = @{ 365 | Enabled = ($Security.authentication.basicAuthentication.enabled -ieq 'true') 366 | Domain = $Security.authentication.basicAuthentication.defaultLogonDomain 367 | LogonMethod = $Security.authentication.basicAuthentication.logonMethod 368 | } 369 | ClientCertificate = @{ 370 | Enabled = ($Security.authentication.clientCertAuthentication.enabled -ieq 'true') 371 | } 372 | Custom = @{ 373 | Providers = @(foreach ($provider in $Security.authentication.customAuthentication.providers.add) { 374 | @{ 375 | Enabled = ($provider.enabled -ieq 'true') 376 | Name = $provider.name 377 | } 378 | }) 379 | } 380 | } 381 | 382 | # ftp security obj 383 | return @{ 384 | DataChannelSecurity = $null 385 | CommandFiltering = $null 386 | Ssl = $_ssl 387 | SslClientCertificates = $null 388 | Authentication = $_auth 389 | CustomAuthorization = @{ 390 | Provider = @{ 391 | Enabled = [bool]$Security.customAuthorization.provider.enabled 392 | Name = $Security.customAuthorization.provider.name 393 | } 394 | } 395 | } 396 | } 397 | 398 | function ConvertTo-IISMFtpAuthorizationObject 399 | { 400 | param( 401 | [Parameter()] 402 | $Section 403 | ) 404 | 405 | $mapped = @{ 406 | Rules = @() 407 | } 408 | 409 | foreach ($rule in $Section.add) { 410 | $obj = @{ 411 | AccessType = $rule.accessType 412 | Users = @($rule.users -split ',').Trim() 413 | Roles = @($rule.roles -split ',').Trim() 414 | Permissions = @($rule.permissions -split ',').Trim() 415 | FullAccess = $false 416 | } 417 | 418 | $obj.FullAccess = (($obj.Permissions -icontains 'read') -and ($obj.Permissions -icontains 'write')) 419 | $mapped.Rules += $obj 420 | } 421 | 422 | return $mapped 423 | } 424 | 425 | function ConvertTo-IISMFtpIPSecurityObject 426 | { 427 | param( 428 | [Parameter()] 429 | $Section 430 | ) 431 | 432 | $mapped = @{ 433 | AllowUnlisted = ($Section.allowUnlisted -ieq 'true') 434 | Rules = @() 435 | } 436 | 437 | foreach ($rule in $Section.add) { 438 | $accessType = 'Allow' 439 | if ($rule.allowed -ieq 'false') { 440 | $accessType = 'Deny' 441 | } 442 | 443 | $subnetMask = $rule.subnetMask 444 | if ([string]::IsNullOrWhiteSpace($subnetMask)) { 445 | $subnetMask = '255.255.255.255' 446 | } 447 | 448 | $obj = @{ 449 | AccessType = $accessType 450 | IPAddress = $rule.ipAddress 451 | SubnetMask = $subnetMask 452 | } 453 | 454 | $mapped.Rules += $obj 455 | } 456 | 457 | return $mapped 458 | } -------------------------------------------------------------------------------- /src/Private/Helpers.ps1: -------------------------------------------------------------------------------- 1 | function Test-IsUnix 2 | { 3 | return $PSVersionTable.Platform -ieq 'unix' 4 | } 5 | 6 | function Invoke-IISMNetshCommand 7 | { 8 | param ( 9 | [Parameter(Mandatory=$true)] 10 | [string] 11 | $Arguments, 12 | 13 | [switch] 14 | $NoError 15 | ) 16 | 17 | $result = (Invoke-Expression -Command "$(Get-IISMNetshPath) $Arguments") 18 | 19 | if ($LASTEXITCODE -ne 0 -and !$NoError) { 20 | throw "Failed to run netsh: $($result)" 21 | } 22 | 23 | return $result 24 | } 25 | 26 | function Invoke-IISMNetCommand 27 | { 28 | param ( 29 | [Parameter(Mandatory=$true)] 30 | [string] 31 | $Arguments, 32 | 33 | [switch] 34 | $NoError 35 | ) 36 | 37 | $result = (Invoke-Expression -Command "$(Get-IISMNetPath) $Arguments 2>&1") 38 | 39 | if ($LASTEXITCODE -ne 0 -and !$NoError) { 40 | throw "Failed to run net: $($result)" 41 | } 42 | 43 | return $result 44 | } 45 | 46 | function Invoke-IISMResetCommand 47 | { 48 | param ( 49 | [Parameter()] 50 | [string] 51 | $Arguments, 52 | 53 | [switch] 54 | $NoError 55 | ) 56 | 57 | $result = (Invoke-Expression -Command "$(Get-IISMResetPath) $Arguments") 58 | 59 | if ($LASTEXITCODE -ne 0 -and !$NoError) { 60 | throw "Failed to run iisreset: $($result)" 61 | } 62 | 63 | return $result 64 | } 65 | 66 | function Get-IISMSiteBindingInformation 67 | { 68 | param ( 69 | [Parameter(Mandatory=$true)] 70 | $Binding 71 | ) 72 | 73 | # get the protocol 74 | $protocol = $Binding.protocol 75 | $info = @{ 76 | IP = $null 77 | Port = $null 78 | Hostname = $null 79 | } 80 | 81 | # get ip, port, hostname 82 | $split = ($Binding.bindingInformation -split ':') 83 | 84 | switch ($protocol.ToLowerInvariant()) { 85 | 'net.tcp' { 86 | $info.Port = $split[0] 87 | $info.Hostname = $split[1] 88 | } 89 | 90 | { @('net.msmq', 'net.pipe', 'msmq.formatname') -icontains $_ } { 91 | $info.Hostname = $split[0] 92 | } 93 | 94 | default { 95 | $info.IP = $split[0] 96 | $info.Port = $split[1] 97 | $info.Hostname = $split[2] 98 | } 99 | } 100 | 101 | # get cert info for https 102 | $cert = $null 103 | if ($protocol -ieq 'https') { 104 | $cert = Get-IISMSiteBindingCertificate -Port $info.Port -IPAddress $info.IP -Hostname $info.Hostname 105 | } 106 | 107 | # set the binding info and return 108 | $info = @{ 109 | Protocol = $protocol 110 | IPAddress = $info.IP 111 | Port = $info.Port 112 | Hostname = $info.Hostname 113 | SslFlags = [bool]$Binding.sslFlags 114 | Certificate = $cert 115 | } 116 | 117 | return $info 118 | } 119 | 120 | function Get-IISMBindingCommandString 121 | { 122 | param( 123 | [Parameter(Mandatory=$true)] 124 | [string] 125 | $Protocol, 126 | 127 | [Parameter()] 128 | [int] 129 | $Port, 130 | 131 | [Parameter()] 132 | [string] 133 | $IPAddress, 134 | 135 | [Parameter()] 136 | [string] 137 | $Hostname, 138 | 139 | [switch] 140 | $SslFlags 141 | ) 142 | 143 | if ([string]::IsNullOrWhiteSpace($IPAddress) -and [string]::IsNullOrWhiteSpace($Hostname) -and $Port -le 0) { 144 | return "bindings.[protocol='$($Protocol)']" 145 | } 146 | 147 | $str = [string]::Empty 148 | 149 | switch ($Protocol.ToLowerInvariant()) { 150 | 'net.tcp' { 151 | $str = "$($Port):$($Hostname)" 152 | } 153 | 154 | { @('net.msmq', 'net.pipe', 'msmq.formatname') -icontains $_ } { 155 | $str = "$($Hostname)" 156 | } 157 | 158 | default { 159 | $str = "$($IPAddress):$($Port):$($Hostname)" 160 | } 161 | } 162 | 163 | $sslFlag = [string]::Empty 164 | if ($Protocol -ieq 'https') { 165 | $sslFlag = ",sslFlags='$(if ($SslFlags) { 1 } else { 0 })'" 166 | } 167 | 168 | return "bindings.[protocol='$($Protocol)',bindingInformation='$($str)'$($sslFlag)]" 169 | } 170 | 171 | function Get-IISMFtpAuthorizationCommandString 172 | { 173 | param( 174 | [Parameter(Mandatory=$true)] 175 | [ValidateSet('Allow', 'Deny')] 176 | [string] 177 | $AccessType, 178 | 179 | [Parameter(Mandatory=$true)] 180 | [ValidateSet('Read', 'Write')] 181 | [string[]] 182 | $Permission, 183 | 184 | [Parameter()] 185 | [string[]] 186 | $User, 187 | 188 | [Parameter()] 189 | [string[]] 190 | $Role 191 | ) 192 | 193 | return "[accessType='$($AccessType)',permissions='$($Permission -join ',')',roles='$($Role -join ',')',users='$($User -join ',')']" 194 | } 195 | 196 | function Get-IISMFtpIPSecurityCommandString 197 | { 198 | param( 199 | [Parameter(Mandatory=$true)] 200 | [ValidateSet('Allow', 'Deny')] 201 | [string] 202 | $AccessType, 203 | 204 | [Parameter(Mandatory=$true)] 205 | [string] 206 | $IPAddress, 207 | 208 | [Parameter()] 209 | [string] 210 | $SubnetMask 211 | ) 212 | 213 | $allowed = ($AccessType -ieq 'Allow') 214 | 215 | if ([string]::IsNullOrWhiteSpace($SubnetMask)) { 216 | $SubnetMask = '255.255.255.255' 217 | } 218 | 219 | return "[allowed='$($allowed)',subnetMask='$($SubnetMask)',ipAddress='$($IPAddress)']" 220 | } 221 | 222 | function Wait-IISMBackgroundTask 223 | { 224 | param ( 225 | [Parameter(Mandatory=$true)] 226 | [scriptblock] 227 | $ScriptBlock 228 | ) 229 | 230 | foreach ($i in (0..10)) { 231 | $result = (. $ScriptBlock) 232 | if ($result) { 233 | return 234 | } 235 | 236 | Start-Sleep -Milliseconds 500 237 | } 238 | 239 | throw 'Resource not created in time' 240 | } 241 | 242 | function Add-IISMSlash 243 | { 244 | param ( 245 | [Parameter()] 246 | [string] 247 | $Value, 248 | 249 | [switch] 250 | $CheckNonEmpty, 251 | 252 | [switch] 253 | $Append 254 | ) 255 | 256 | if ($CheckNonEmpty -and [string]::IsNullOrWhiteSpace($Value)) { 257 | return $Value 258 | } 259 | 260 | if ($Append) { 261 | if (!$Value.EndsWith('/')) { 262 | $Value = "$($Value)/" 263 | } 264 | } 265 | else { 266 | if (!$Value.StartsWith('/')) { 267 | $Value = "/$($Value)" 268 | } 269 | } 270 | 271 | return $Value 272 | } 273 | 274 | function Protect-IISMValue 275 | { 276 | param ( 277 | [Parameter()] 278 | $Value1, 279 | 280 | [Parameter()] 281 | $Value2 282 | ) 283 | 284 | if (($null -eq $Value1) -or [string]::IsNullOrWhiteSpace($Value1)) { 285 | return $Value2 286 | } 287 | 288 | return $Value1 289 | } 290 | 291 | function Get-IISMCredentialDetails 292 | { 293 | param( 294 | [Parameter(Mandatory=$true)] 295 | [pscredential] 296 | $Credentials 297 | ) 298 | 299 | $domain = $Credentials.GetNetworkCredential().Domain 300 | $username = $Credentials.GetNetworkCredential().UserName 301 | $password = $Credentials.GetNetworkCredential().Password 302 | 303 | if (![string]::IsNullOrWhiteSpace($domain)) { 304 | $username = "$($domain)\$($username)" 305 | } 306 | 307 | return @{ 308 | Username = $username 309 | Password = $password 310 | } 311 | } 312 | 313 | function Split-IISMAppName 314 | { 315 | param( 316 | [Parameter(Mandatory=$true)] 317 | [string] 318 | $AppName 319 | ) 320 | 321 | $atoms = @($AppName -split '/') 322 | 323 | $_siteName = $atoms[0] 324 | $_appName = '/' 325 | 326 | if ($atoms.Length -gt 1) { 327 | $_appName = ($atoms[1..($atoms.Length - 1)] -join '/') 328 | } 329 | 330 | return @{ 331 | SiteName = $_siteName 332 | AppName = $_appName 333 | } 334 | } 335 | 336 | function Split-IISMDirectoryName 337 | { 338 | param( 339 | [Parameter(Mandatory=$true)] 340 | [string] 341 | $DirName 342 | ) 343 | 344 | $atoms = @($DirName -split '/') 345 | 346 | $_siteName = $atoms[0] 347 | $_appName = '/' 348 | $_dirName = [string]::Empty 349 | 350 | # if name ends with a slash, it's a app 351 | if ($DirName.EndsWith('/')) { 352 | $atoms = $atoms[0..($atoms.Length - 2)] 353 | if ($atoms.Length -gt 1) { 354 | $_appName = ($atoms[1..($atoms.Length - 1)] -join '/') 355 | } 356 | } 357 | 358 | # else it's a vdir 359 | else { 360 | $_dirName = $atoms[$atoms.Length - 1] 361 | 362 | if ($atoms.Length -gt 2) { 363 | $_appName = ($atoms[1..($atoms.Length - 2)] -join '/') 364 | } 365 | } 366 | 367 | return @{ 368 | SiteName = $_siteName 369 | AppName = $_appName 370 | DirName = $_dirName 371 | } 372 | } 373 | 374 | function Get-IISMFtpDirectoryAuthorizationInternal 375 | { 376 | param( 377 | [Parameter(Mandatory=$true)] 378 | [string] 379 | $Name 380 | ) 381 | 382 | # get the rules 383 | $result = Invoke-IISMAppCommand -Arguments "list config '$($Name)' /section:system.ftpServer/security/authorization" 384 | 385 | # just return if there are no results 386 | if ($null -eq $result.CONFIG) { 387 | return $null 388 | } 389 | 390 | return (ConvertTo-IISMFtpAuthorizationObject -Section $result.CONFIG.'system.ftpServer-security-authorization') 391 | } 392 | 393 | function Get-IISMFtpDirectoryIPSecurityInternal 394 | { 395 | param( 396 | [Parameter(Mandatory=$true)] 397 | [string] 398 | $Name 399 | ) 400 | 401 | # get the rules 402 | $result = Invoke-IISMAppCommand -Arguments "list config '$($Name)' /section:system.ftpServer/security/ipSecurity" 403 | 404 | # just return if there are no results 405 | if ($null -eq $result.CONFIG) { 406 | return $null 407 | } 408 | 409 | return (ConvertTo-IISMFtpIPSecurityObject -Section $result.CONFIG.'system.ftpServer-security-ipSecurity') 410 | } -------------------------------------------------------------------------------- /src/Private/Paths.ps1: -------------------------------------------------------------------------------- 1 | function Get-IISMHomePath 2 | { 3 | if (Test-IsUnix) { 4 | return "/mnt/c/Windows/System32" 5 | } 6 | else { 7 | return "$($env:SystemDrive)/Windows/System32" 8 | } 9 | } 10 | 11 | function Get-IISMAppCmdPath 12 | { 13 | return (Join-Path (Get-IISMHomePath) (Join-Path 'inetsrv' 'appcmd.exe')) 14 | } 15 | 16 | function Get-IISMNetshPath 17 | { 18 | return (Join-Path (Get-IISMHomePath) 'netsh.exe') 19 | } 20 | 21 | function Get-IISMNetPath 22 | { 23 | return (Join-Path (Get-IISMHomePath) 'net.exe') 24 | } 25 | 26 | function Get-IISMResetPath 27 | { 28 | return (Join-Path (Get-IISMHomePath) 'iisreset.exe') 29 | } 30 | 31 | function Get-IISMSiteDefaultLogPath 32 | { 33 | return "$($env:SystemDrive)/inetpub/logs/LogFiles" 34 | } 35 | 36 | function Get-IISMSiteDefaultLogFields 37 | { 38 | $fields = @( 39 | 'Date', 40 | 'Time', 41 | 'ServerIP', 42 | 'Method', 43 | 'UriStem', 44 | 'UriQuery', 45 | 'ServerPort', 46 | 'UserName', 47 | 'ClientIP', 48 | 'UserAgent', 49 | 'Referer', 50 | 'HttpStatus', 51 | 'HttpSubStatus', 52 | 'TimeTaken' 53 | ) 54 | 55 | return ($fields -join ',') 56 | } 57 | 58 | function Get-IISMFtpSiteDefaultLogFields 59 | { 60 | $fields = @( 61 | 'Date', 62 | 'Time', 63 | 'ClientIP', 64 | 'UserName', 65 | 'ServerIP', 66 | 'Method', 67 | 'UriStem', 68 | 'FtpStatus', 69 | 'Win32Status', 70 | 'ServerPort', 71 | 'FtpSubStatus', 72 | 'Session', 73 | 'FullPath' 74 | ) 75 | 76 | return ($fields -join ',') 77 | } -------------------------------------------------------------------------------- /src/Public/AppPools.ps1: -------------------------------------------------------------------------------- 1 | function Get-IISMAppPool 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [Parameter()] 6 | [string] 7 | $Name 8 | ) 9 | 10 | if (![string]::IsNullOrWhiteSpace($Name)) { 11 | $result = Invoke-IISMAppCommand -Arguments "list apppool '$($Name)'" -NoError 12 | } 13 | else { 14 | $result = Invoke-IISMAppCommand -Arguments 'list apppools' -NoError 15 | } 16 | 17 | if ($null -eq $result.APPPOOL) { 18 | return $null 19 | } 20 | 21 | return (ConvertTo-IISMAppPoolObject -AppPools $result.APPPOOL) 22 | } 23 | 24 | function Get-IISMAppPools 25 | { 26 | [CmdletBinding()] 27 | param ( 28 | [Parameter()] 29 | [string[]] 30 | $Names 31 | ) 32 | 33 | return @(foreach ($name in $Names) { Get-IISMAppPool -Name $name }) 34 | } 35 | 36 | function Test-IISMAppPool 37 | { 38 | [CmdletBinding()] 39 | param ( 40 | [Parameter(Mandatory=$true)] 41 | [string] 42 | $Name 43 | ) 44 | 45 | return ($null -ne (Get-IISMAppPool -Name $Name)) 46 | } 47 | 48 | function Test-IISMAppPoolRunning 49 | { 50 | [CmdletBinding()] 51 | param ( 52 | [Parameter(Mandatory=$true)] 53 | [string] 54 | $Name 55 | ) 56 | 57 | return ((Get-IISMAppPool -Name $Name).State -ieq 'started') 58 | } 59 | 60 | function Stop-IISMAppPool 61 | { 62 | [CmdletBinding()] 63 | param ( 64 | [Parameter(Mandatory=$true)] 65 | [string] 66 | $Name 67 | ) 68 | 69 | if (!(Test-IISMAppPoolRunning -Name $Name)) { 70 | return 71 | } 72 | 73 | Invoke-IISMAppCommand -Arguments "stop apppool '$($Name)'" -NoParse | Out-Null 74 | return (Get-IISMAppPool -Name $Name) 75 | } 76 | 77 | function Start-IISMAppPool 78 | { 79 | [CmdletBinding()] 80 | param ( 81 | [Parameter(Mandatory=$true)] 82 | [string] 83 | $Name 84 | ) 85 | 86 | if (Test-IISMAppPoolRunning -Name $Name) { 87 | return 88 | } 89 | 90 | Invoke-IISMAppCommand -Arguments "start apppool '$($Name)'" -NoParse | Out-Null 91 | return (Get-IISMAppPool -Name $Name) 92 | } 93 | 94 | function Restart-IISMAppPool 95 | { 96 | [CmdletBinding()] 97 | param ( 98 | [Parameter(Mandatory=$true)] 99 | [string] 100 | $Name 101 | ) 102 | 103 | Stop-IISMAppPool -Name $Name | Out-Null 104 | Start-IISMAppPool -Name $Name | Out-Null 105 | return (Get-IISMAppPool -Name $Name) 106 | } 107 | 108 | function Reset-IISMAppPool 109 | { 110 | [CmdletBinding()] 111 | param ( 112 | [Parameter(Mandatory=$true)] 113 | [string] 114 | $Name 115 | ) 116 | 117 | if (!(Test-IISMAppPoolRunning -Name $Name)) { 118 | return 119 | } 120 | 121 | Invoke-IISMAppCommand -Arguments "recycle apppool '$($Name)'" -NoParse | Out-Null 122 | return (Get-IISMAppPool -Name $Name) 123 | } 124 | 125 | function Remove-IISMAppPool 126 | { 127 | [CmdletBinding()] 128 | param ( 129 | [Parameter(Mandatory=$true)] 130 | [string] 131 | $Name 132 | ) 133 | 134 | if (!(Test-IISMAppPool -Name $Name)) { 135 | return 136 | } 137 | 138 | Invoke-IISMAppCommand -Arguments "delete apppool '$($Name)'" -NoParse | Out-Null 139 | return (Get-IISMAppPool) 140 | } 141 | 142 | function New-IISMAppPool 143 | { 144 | [CmdletBinding()] 145 | param ( 146 | [Parameter(Mandatory=$true)] 147 | [string] 148 | $Name, 149 | 150 | [Parameter()] 151 | [ValidateSet('2.0', '4.0')] 152 | [string] 153 | $RuntimeVersion = '4.0', 154 | 155 | [Parameter()] 156 | [ValidateSet('Classic', 'Integrated')] 157 | [string] 158 | $PipelineMode = 'Integrated', 159 | 160 | [switch] 161 | $Enable32Bit 162 | ) 163 | 164 | # error if app-pool already exists 165 | if (Test-IISMAppPool -Name $Name) { 166 | throw "Application Pool '$($Name)' already exists in IIS" 167 | } 168 | 169 | # create the app-pool 170 | $_args = "/name:'$($Name)' /managedRuntimeVersion:v$($RuntimeVersion) /managedPipelineMode:$($PipelineMode) /enable32BitAppOnWin64:$($Enable32Bit)" 171 | Invoke-IISMAppCommand -Arguments "add apppool $($_args)" -NoParse | Out-Null 172 | Wait-IISMBackgroundTask -ScriptBlock { Test-IISMAppPool -Name $Name } 173 | 174 | # return the app-pool 175 | return (Get-IISMAppPool -Name $Name) 176 | } 177 | 178 | function Update-IISMAppPool 179 | { 180 | [CmdletBinding()] 181 | param ( 182 | [Parameter(Mandatory=$true)] 183 | [string] 184 | $Name, 185 | 186 | [Parameter()] 187 | [ValidateSet('', '2.0', '4.0')] 188 | [string] 189 | $RuntimeVersion = '', 190 | 191 | [Parameter()] 192 | [ValidateSet('', 'Classic', 'Integrated')] 193 | [string] 194 | $PipelineMode = '', 195 | 196 | [Parameter()] 197 | [int] 198 | $QueueLength = 0 199 | ) 200 | 201 | # error if the app-pool doesn't exist 202 | if (!(Test-IISMAppPool -Name $Name)) { 203 | throw "Application Pool '$($Name)' does not exist in IIS" 204 | } 205 | 206 | # update the runtime 207 | if (![string]::IsNullOrWhiteSpace($RuntimeVersion)) { 208 | Invoke-IISMAppCommand -Arguments "set apppool '$($Name)' /managedRuntimeVersion:v$($RuntimeVersion)" -NoParse | Out-Null 209 | } 210 | 211 | # update the pipeline mode 212 | if (![string]::IsNullOrWhiteSpace($PipelineMode)) { 213 | Invoke-IISMAppCommand -Arguments "set apppool '$($Name)' /managedPipelineMode:$($PipelineMode)" -NoParse | Out-Null 214 | } 215 | 216 | # update the queue length 217 | if ($QueueLength -gt 0) { 218 | Invoke-IISMAppCommand -Arguments "set apppool '$($Name)' /queueLength:$($QueueLength)" -NoParse | Out-Null 219 | } 220 | 221 | # return the app-pool 222 | return (Get-IISMAppPool -Name $Name) 223 | } 224 | 225 | function Update-IISMAppPoolProcessModel 226 | { 227 | [CmdletBinding()] 228 | param ( 229 | [Parameter(Mandatory=$true)] 230 | [string] 231 | $Name, 232 | 233 | [Parameter()] 234 | [ValidateSet('', 'ApplicationPoolIdentity', 'LocalService', 'LocalSystem', 'NetworkService', 'SpecificUser')] 235 | [string] 236 | $IdentifyType = '', 237 | 238 | [Parameter()] 239 | [pscredential] 240 | $Credentials, 241 | 242 | [Parameter()] 243 | [int] 244 | $IdleTimeOut = -1, 245 | 246 | [Parameter()] 247 | [ValidateSet('', 'Terminate', 'Suspend')] 248 | [string] 249 | $IdleTimeOutAction = '', 250 | 251 | [Parameter()] 252 | [int] 253 | $WorkerProcesses = -1 254 | ) 255 | 256 | # error if the app-pool doesn't exist 257 | if (!(Test-IISMAppPool -Name $Name)) { 258 | throw "Application Pool '$($Name)' does not exist in IIS" 259 | } 260 | 261 | # set the idle timeout 262 | if ($IdleTimeOut -ge 0) { 263 | $strTimeout = [timespan]::FromMinutes($IdleTimeOut).ToString() 264 | Invoke-IISMAppCommand -Arguments "set apppool '$($Name)' /processModel.idleTimeout:$($strTimeout)" -NoParse | Out-Null 265 | } 266 | 267 | # set the idle timeout action 268 | if (![string]::IsNullOrWhiteSpace($IdleTimeOutAction)) { 269 | Invoke-IISMAppCommand -Arguments "set apppool '$($Name)' /processModel.idleTimeoutAction:$($IdleTimeOutAction)" -NoParse | Out-Null 270 | } 271 | 272 | # set the max worker processes 273 | if ($WorkerProcesses -ge 0) { 274 | Invoke-IISMAppCommand -Arguments "set apppool '$($Name)' /processModel.maxProcesses:$($WorkerProcesses)" -NoParse | Out-Null 275 | } 276 | 277 | # set the user identity 278 | if (![string]::IsNullOrWhiteSpace($IdentifyType)) { 279 | $_args = "/processModel.identityType:$($IdentifyType)" 280 | 281 | # setup as specific user with creds 282 | if ($IdentifyType -ieq 'SpecificUser') { 283 | if ($null -eq $Credentials) { 284 | throw "No credentials supplied when attempting to set the '$($Name)' application pool to run as SpecificUser" 285 | } 286 | 287 | $creds = Get-IISMCredentialDetails -Credentials $Credentials 288 | $_args += " /processModel.userName:$($creds.username) /processModel.password:$($creds.password)" 289 | } 290 | 291 | Invoke-IISMAppCommand -Arguments "set apppool '$($Name)' $($_args)" -NoParse | Out-Null 292 | } 293 | 294 | # return the app-pool 295 | return (Get-IISMAppPool -Name $Name) 296 | } 297 | 298 | function Update-IISMAppPoolRecycling 299 | { 300 | [CmdletBinding()] 301 | param ( 302 | [Parameter(Mandatory=$true)] 303 | [string] 304 | $Name, 305 | 306 | [Parameter()] 307 | [int] 308 | $RecycleInterval = -1, 309 | 310 | [Parameter()] 311 | [timespan[]] 312 | $RecycleTimes = $null 313 | ) 314 | 315 | # error if the app-pool doesn't exist 316 | if (!(Test-IISMAppPool -Name $Name)) { 317 | throw "Application Pool '$($Name)' does not exist in IIS" 318 | } 319 | 320 | # set a recycle interval 321 | if ($RecycleInterval -ge 0) { 322 | $strInterval = [timespan]::FromMinutes($RecycleInterval).ToString() 323 | Invoke-IISMAppCommand -Arguments "set apppool '$($Name)' /recycling.periodicRestart.time:$($strInterval)" -NoParse | Out-Null 324 | } 325 | 326 | # set recycling times 327 | if (($RecycleTimes | Measure-Object).Count -gt 0) { 328 | # remove all current times 329 | Invoke-IISMAppCommand -Arguments "set apppool '$($Name)' /-recycling.periodicRestart.schedule" -NoParse | Out-Null 330 | 331 | # add the new times 332 | foreach ($time in @($RecycleTimes)) { 333 | Invoke-IISMAppCommand -Arguments "set apppool '$($Name)' /+`"recycling.periodicRestart.schedule.[value='$($time.ToString())']`"" -NoParse | Out-Null 334 | } 335 | } 336 | 337 | # return the app-pool 338 | return (Get-IISMAppPool -Name $Name) 339 | } 340 | -------------------------------------------------------------------------------- /src/Public/Apps.ps1: -------------------------------------------------------------------------------- 1 | function Get-IISMApp 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [Parameter()] 6 | [string] 7 | $SiteName, 8 | 9 | [Parameter()] 10 | [string] 11 | $Name, 12 | 13 | [switch] 14 | $Quick 15 | ) 16 | 17 | $Name = Add-IISMSlash -Value $Name 18 | $AppName = "$($SiteName)$($Name)" 19 | 20 | if (![string]::IsNullOrWhiteSpace($SiteName)) { 21 | $result = Invoke-IISMAppCommand -Arguments "list app '$($AppName)'" -NoError 22 | } 23 | else { 24 | $result = Invoke-IISMAppCommand -Arguments 'list apps' -NoError 25 | } 26 | 27 | if ($null -eq $result.APP) { 28 | return $null 29 | } 30 | 31 | ConvertTo-IISMAppObject -Apps $result.APP -Quick:$Quick 32 | } 33 | 34 | function Test-IISMApp 35 | { 36 | [CmdletBinding()] 37 | param ( 38 | [Parameter(Mandatory=$true)] 39 | [string] 40 | $SiteName, 41 | 42 | [Parameter()] 43 | [string] 44 | $Name = '/' 45 | ) 46 | 47 | return ($null -ne (Get-IISMApp -SiteName $SiteName -Name $Name -Quick)) 48 | } 49 | 50 | function Remove-IISMApp 51 | { 52 | [CmdletBinding()] 53 | param ( 54 | [Parameter(Mandatory=$true)] 55 | [string] 56 | $SiteName, 57 | 58 | [Parameter()] 59 | [string] 60 | $Name = '/', 61 | 62 | [switch] 63 | $NoOutput 64 | ) 65 | 66 | $Name = Add-IISMSlash -Value $Name 67 | 68 | if (Test-IISMApp -SiteName $SiteName -Name $Name) { 69 | Invoke-IISMAppCommand -Arguments "delete app '$($SiteName)$($Name)'" -NoParse | Out-Null 70 | } 71 | 72 | if (!$NoOutput) { 73 | return (Get-IISMApp) 74 | } 75 | } 76 | 77 | function New-IISMApp 78 | { 79 | [CmdletBinding()] 80 | param ( 81 | [Parameter(Mandatory=$true)] 82 | [string] 83 | $SiteName, 84 | 85 | [Parameter()] 86 | [string] 87 | $Name = '/', 88 | 89 | [Parameter(Mandatory=$true)] 90 | [string] 91 | $PhysicalPath, 92 | 93 | [Parameter()] 94 | [pscredential] 95 | $Credentials, 96 | 97 | [Parameter()] 98 | [string] 99 | $AppPoolName, 100 | 101 | [switch] 102 | $CreatePath, 103 | 104 | [switch] 105 | $NoOutput 106 | ) 107 | 108 | $Name = Add-IISMSlash -Value $Name 109 | 110 | # error if app already exists 111 | if (Test-IISMApp -SiteName $SiteName -Name $Name) { 112 | throw "Application '$($SiteName)$($Name)' already exists in IIS" 113 | } 114 | 115 | # create the app 116 | $_args = "/site.name:'$($SiteName)' /path:$($Name) /physicalPath:'$($PhysicalPath)'" 117 | 118 | # if app-pool supplied, set it. if it doesn't exist, create a default one 119 | if (![string]::IsNullOrWhiteSpace($AppPoolName)) { 120 | if (!(Test-IISMAppPool -Name $AppPoolName)) { 121 | New-IISMAppPool -Name $AppPoolName | Out-Null 122 | } 123 | 124 | $_args += " /applicationPool:'$($AppPoolName)'" 125 | } 126 | 127 | # if create flag passed, make the path 128 | if ($CreatePath -and !(Test-Path $PhysicalPath)) { 129 | New-Item -Path $PhysicalPath -ItemType Directory -Force | Out-Null 130 | } 131 | 132 | Invoke-IISMAppCommand -Arguments "add app $($_args)" -NoParse | Out-Null 133 | Wait-IISMBackgroundTask -ScriptBlock { Test-IISMApp -SiteName $SiteName -Name $Name } 134 | 135 | # set the physical vdir path creds 136 | if ($null -ne $Credentials) { 137 | Set-IISMDirectoryCredentials -SiteName $SiteName -AppName $Name -Credentials $Credentials 138 | } 139 | 140 | # return the app 141 | if (!$NoOutput) { 142 | return (Get-IISMApp -SiteName $SiteName -Name $Name) 143 | } 144 | } 145 | 146 | function Update-IISMApp 147 | { 148 | [CmdletBinding()] 149 | param ( 150 | [Parameter(Mandatory=$true)] 151 | [string] 152 | $SiteName, 153 | 154 | [Parameter()] 155 | [string] 156 | $Name = '/', 157 | 158 | [Parameter()] 159 | [string] 160 | $PhysicalPath, 161 | 162 | [Parameter()] 163 | [string] 164 | $AppPoolName, 165 | 166 | [switch] 167 | $NoOutput 168 | ) 169 | 170 | $Name = Add-IISMSlash -Value $Name 171 | $AppName = "$($SiteName)$($Name)" 172 | 173 | # error if app doesn't exists 174 | if (!(Test-IISMApp -SiteName $SiteName -Name $Name)) { 175 | throw "Application '$($AppName)' does not exist in IIS" 176 | } 177 | 178 | # update the physical path 179 | if (![string]::IsNullOrWhiteSpace($PhysicalPath)) { 180 | Invoke-IISMAppCommand -Arguments "set app '$($AppName)' /physicalPath:'$($PhysicalPath)'" -NoParse | Out-Null 181 | } 182 | 183 | # update the application pool 184 | if (![string]::IsNullOrWhiteSpace($AppPoolName)) { 185 | Invoke-IISMAppCommand -Arguments "set app '$($AppName)' /applicationPool:'$($AppPoolName)'" -NoParse | Out-Null 186 | } 187 | 188 | # return the app 189 | if (!$NoOutput) { 190 | return (Get-IISMApp -SiteName $SiteName -Name $Name) 191 | } 192 | } -------------------------------------------------------------------------------- /src/Public/Directories.ps1: -------------------------------------------------------------------------------- 1 | function Get-IISMDirectory 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [Parameter()] 6 | [string] 7 | $SiteName, 8 | 9 | [Parameter()] 10 | [string] 11 | $AppName = '/', 12 | 13 | [Parameter()] 14 | [string] 15 | $DirName, 16 | 17 | [Parameter()] 18 | [string] 19 | $PhysicalPath, 20 | 21 | [switch] 22 | $Quick 23 | ) 24 | 25 | $AppName = Add-IISMSlash -Value $AppName 26 | $Name = "$($SiteName)$($AppName)" 27 | 28 | # get the directories 29 | $result = (Invoke-IISMAppCommand -Arguments 'list vdirs' -NoError) 30 | 31 | # just return if there are no results 32 | if ($null -eq $result.VDIR) { 33 | return $null 34 | } 35 | 36 | $dirs = ConvertTo-IISMDirectoryObject -Directories $result.VDIR -Quick:$Quick 37 | 38 | # filter by site/app 39 | if (![string]::IsNullOrWhiteSpace($SiteName)) { 40 | $dirs = @($dirs | Where-Object { $_.AppName -ieq $Name }) 41 | } 42 | 43 | # then filter by dir 44 | if (![string]::IsNullOrWhiteSpace($DirName)) { 45 | $DirName = Add-IISMSlash -Value $DirName 46 | $dirs = @($dirs | Where-Object { $_.Path -ieq $DirName }) 47 | } 48 | 49 | # if we have a physical path, filter dirs 50 | if (![string]::IsNullOrWhiteSpace($PhysicalPath)) { 51 | $dirs = @($dirs | Where-Object { $_.PhysicalPath -ieq $PhysicalPath }) 52 | } 53 | 54 | return $dirs 55 | } 56 | 57 | function Test-IISMDirectory 58 | { 59 | [CmdletBinding()] 60 | param ( 61 | [Parameter(Mandatory=$true)] 62 | [string] 63 | $SiteName, 64 | 65 | [Parameter()] 66 | [string] 67 | $AppName = '/', 68 | 69 | [Parameter()] 70 | [string] 71 | $DirName 72 | ) 73 | 74 | return ($null -ne (Get-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName -Quick)) 75 | } 76 | 77 | function Remove-IISMDirectory 78 | { 79 | [CmdletBinding()] 80 | param ( 81 | [Parameter(Mandatory=$true)] 82 | [string] 83 | $SiteName, 84 | 85 | [Parameter()] 86 | [string] 87 | $AppName = '/', 88 | 89 | [Parameter()] 90 | [string] 91 | $DirName, 92 | 93 | [switch] 94 | $NoOutput 95 | ) 96 | 97 | $AppName = Add-IISMSlash -Value $AppName 98 | 99 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 100 | if (![string]::IsNullOrWhiteSpace($DirName)) { 101 | $Name = "$($Name)$($DirName)" 102 | } 103 | 104 | if (Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName) { 105 | Invoke-IISMAppCommand -Arguments "delete vdir '$($Name)'" -NoParse | Out-Null 106 | } 107 | 108 | if (!$NoOutput) { 109 | return (Get-IISMDirectory) 110 | } 111 | } 112 | 113 | function New-IISMDirectory 114 | { 115 | [CmdletBinding()] 116 | param ( 117 | [Parameter(Mandatory=$true)] 118 | [string] 119 | $SiteName, 120 | 121 | [Parameter()] 122 | [string] 123 | $AppName = '/', 124 | 125 | [Parameter(Mandatory=$true)] 126 | [string] 127 | $DirName, 128 | 129 | [Parameter(Mandatory=$true)] 130 | [string] 131 | $PhysicalPath, 132 | 133 | [Parameter()] 134 | [pscredential] 135 | $Credentials, 136 | 137 | [switch] 138 | $CreatePath, 139 | 140 | [switch] 141 | $NoOutput 142 | ) 143 | 144 | $AppName = Add-IISMSlash -Value $AppName 145 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 146 | $FullDirName = "$($Name)$($DirName)" 147 | 148 | # error if directory already exists 149 | if (Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName) { 150 | throw "Directory '$($FullDirName)' already exists in IIS" 151 | } 152 | 153 | # error if the app doesn't exist 154 | if (!(Test-IISMApp -SiteName $SiteName -Name $AppName)) { 155 | throw "Application '$($Name)' does not exist in IIS" 156 | } 157 | 158 | # if create flag passed, make the path 159 | if ($CreatePath -and !(Test-Path $PhysicalPath)) { 160 | New-Item -Path $PhysicalPath -ItemType Directory -Force | Out-Null 161 | } 162 | 163 | # create the directory 164 | $_dirName = Add-IISMSlash -Value $DirName 165 | $_args = "/app.name:'$($Name)' /path:'$($_dirName)' /physicalPath:'$($PhysicalPath)'" 166 | 167 | Invoke-IISMAppCommand -Arguments "add vdir $($_args)" -NoParse | Out-Null 168 | Wait-IISMBackgroundTask -ScriptBlock { Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName } 169 | 170 | # set the creds 171 | if ($null -ne $Credentials) { 172 | Set-IISMDirectoryCredentials -SiteName $SiteName -AppName $AppName -DirName $DirName -Credentials $Credentials 173 | } 174 | 175 | # return the directory 176 | if (!$NoOutput) { 177 | return (Get-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName) 178 | } 179 | } 180 | 181 | function Update-IISMDirectory 182 | { 183 | [CmdletBinding()] 184 | param ( 185 | [Parameter(Mandatory=$true)] 186 | [string] 187 | $SiteName, 188 | 189 | [Parameter()] 190 | [string] 191 | $AppName = '/', 192 | 193 | [Parameter()] 194 | [string] 195 | $DirName, 196 | 197 | [Parameter()] 198 | [string] 199 | $PhysicalPath, 200 | 201 | [Parameter()] 202 | [pscredential] 203 | $Credentials, 204 | 205 | [switch] 206 | $NoOutput 207 | ) 208 | 209 | $AppName = Add-IISMSlash -Value $AppName 210 | 211 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 212 | if (![string]::IsNullOrWhiteSpace($DirName)) { 213 | $Name = "$($Name)$($DirName)" 214 | } 215 | 216 | # error if the directory doesn't exist 217 | if (!(Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName)) { 218 | throw "Directory '$($Name)' does not exist in IIS" 219 | } 220 | 221 | # update the physical path 222 | if (![string]::IsNullOrWhiteSpace($PhysicalPath)) { 223 | Invoke-IISMAppCommand -Arguments "set vdir '$($Name)' /physicalPath:'$($PhysicalPath)'" -NoParse | Out-Null 224 | } 225 | 226 | # update the credentials 227 | if ($null -ne $Credentials) { 228 | Set-IISMDirectoryCredentials -SiteName $SiteName -AppName $AppName -DirName $DirName -Credentials $Credentials 229 | } 230 | 231 | # return the directory 232 | if (!$NoOutput) { 233 | return (Get-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName) 234 | } 235 | } 236 | 237 | function Update-IISMDirectoryPhysicalPaths 238 | { 239 | [CmdletBinding()] 240 | param ( 241 | [Parameter(Mandatory=$true)] 242 | [string] 243 | $From, 244 | 245 | [Parameter(Mandatory=$true)] 246 | [string] 247 | $To, 248 | 249 | [switch] 250 | $NoOutput 251 | ) 252 | 253 | # get all directories with the From path 254 | $dirs = Get-IISMDirectory -PhysicalPath $From 255 | 256 | # update each dir 257 | foreach ($dir in $dirs) { 258 | $info = Split-IISMDirectoryName -DirName $dir.Name 259 | Update-IISMDirectory -SiteName $info.SiteName -AppName $info.AppName -DirName $info.DirName -PhysicalPath $To | Out-Null 260 | } 261 | 262 | # return the directories 263 | if (!$NoOutput) { 264 | return (Get-IISMDirectory -PhysicalPath $To) 265 | } 266 | } 267 | 268 | function Mount-IISMDirectoryShare 269 | { 270 | [CmdletBinding()] 271 | param ( 272 | [Parameter(Mandatory=$true)] 273 | [string] 274 | $SiteName, 275 | 276 | [Parameter()] 277 | [string] 278 | $AppName = '/', 279 | 280 | [Parameter()] 281 | [string] 282 | $DirName, 283 | 284 | [Parameter()] 285 | [string] 286 | $Permission = 'Everyone,FULL', 287 | 288 | [switch] 289 | $NoOutput 290 | ) 291 | 292 | $AppName = Add-IISMSlash -Value $AppName 293 | $DirName = Add-IISMSlash -Value $DirName 294 | 295 | # error if the site doesn't exist 296 | if (!(Test-IISMSite -Name $SiteName)) { 297 | throw "Website '$($SiteName)' does not exist in IIS" 298 | } 299 | 300 | # error if the app doesn't exist 301 | if (!(Test-IISMApp -SiteName $SiteName -Name $AppName)) { 302 | throw "Application '$($SiteName)$($AppName)' does not exist in IIS" 303 | } 304 | 305 | # get the physical path for the site/app 306 | $path = Get-IISMSitePhysicalPath -Name $SiteName -AppName $AppName -DirName $DirName 307 | 308 | # error if the path doesn't exist 309 | if ([string]::IsNullOrWhiteSpace($path) -or !(Test-Path $path)) { 310 | throw "The path for sharing does not exist: $($path)" 311 | } 312 | 313 | # make the share name 314 | $ShareName = ("$($SiteName)$($AppName)$($DirName)".Trim('\/') -replace '[\\/]', '.') 315 | 316 | # if the share exists, remove it 317 | Remove-IISMDirectoryShare -SiteName $SiteName -AppName $AppName -DirName $DirName 318 | 319 | # create the share 320 | Invoke-IISMNetCommand -Arguments "share $($ShareName)=$($path) /grant:`"$($Permission)`"" | Out-Null 321 | 322 | # return the share details 323 | if (!$NoOutput) { 324 | return (Get-IISMDirectoryShare -SiteName $SiteName -AppName $AppName -DirName $DirName) 325 | } 326 | } 327 | 328 | function Remove-IISMDirectoryShare 329 | { 330 | [CmdletBinding()] 331 | param ( 332 | [Parameter(Mandatory=$true)] 333 | [string] 334 | $SiteName, 335 | 336 | [Parameter()] 337 | [string] 338 | $AppName = '/', 339 | 340 | [Parameter()] 341 | [string] 342 | $DirName 343 | ) 344 | 345 | # make the share name 346 | $AppName = Add-IISMSlash -Value $AppName 347 | $DirName = Add-IISMSlash -Value $DirName 348 | $ShareName = ("$($SiteName)$($AppName)$($DirName)".Trim('\/') -replace '[\\/]', '.') 349 | 350 | # if the share exists, remove it 351 | if (Test-IISMDirectoryShare -SiteName $SiteName -AppName $AppName -DirName $DirName) { 352 | Invoke-IISMNetCommand -Arguments "share $($ShareName) /delete /y" | Out-Null 353 | } 354 | } 355 | 356 | function Test-IISMDirectoryShare 357 | { 358 | [CmdletBinding()] 359 | param ( 360 | [Parameter(Mandatory=$true)] 361 | [string] 362 | $SiteName, 363 | 364 | [Parameter()] 365 | [string] 366 | $AppName = '/', 367 | 368 | [Parameter()] 369 | [string] 370 | $DirName 371 | ) 372 | 373 | return ($null -ne (Get-IISMDirectoryShare -SiteName $SiteName -AppName $AppName -DirName $DirName)) 374 | } 375 | 376 | function Get-IISMDirectoryShare 377 | { 378 | [CmdletBinding()] 379 | param ( 380 | [Parameter(Mandatory=$true)] 381 | [string] 382 | $SiteName, 383 | 384 | [Parameter()] 385 | [string] 386 | $AppName = '/', 387 | 388 | [Parameter()] 389 | [string] 390 | $DirName 391 | ) 392 | 393 | # make the share name 394 | $AppName = Add-IISMSlash -Value $AppName 395 | $DirName = Add-IISMSlash -Value $DirName 396 | $ShareName = ("$($SiteName)$($AppName)$($DirName)".Trim('\/') -replace '[\\/]', '.') 397 | 398 | # check if the share exists 399 | $share = (Invoke-IISMNetCommand -Arguments "share $($ShareName)" -NoError) 400 | if (($LASTEXITCODE -ne 0) -or ($share -ilike '*does not exist*')) { 401 | return $null 402 | } 403 | 404 | # if it exists, parse the data 405 | $obj = @{} 406 | $culture = (Get-Culture).TextInfo 407 | 408 | foreach ($shr in @($share -imatch '\s{2,}')) { 409 | $atoms = ($shr -split '\s{2,}') 410 | $name = ($culture.ToTitleCase($atoms[0]) -ireplace '\s+', '') 411 | $obj[$name] = $atoms[1] 412 | } 413 | 414 | return $obj 415 | } 416 | 417 | function Set-IISMDirectoryCredentials 418 | { 419 | [CmdletBinding()] 420 | param( 421 | [Parameter(Mandatory=$true)] 422 | [string] 423 | $SiteName, 424 | 425 | [Parameter()] 426 | [string] 427 | $AppName = '/', 428 | 429 | [Parameter()] 430 | [string] 431 | $DirName, 432 | 433 | [Parameter(Mandatory=$true)] 434 | [pscredential] 435 | $Credentials 436 | ) 437 | 438 | $AppName = Add-IISMSlash -Value $AppName 439 | 440 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 441 | if (![string]::IsNullOrWhiteSpace($DirName)) { 442 | $Name = "$($Name)$($DirName)" 443 | } 444 | 445 | # error if the directory doesn't exist 446 | if (!(Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName)) { 447 | throw "Directory '$($Name)' does not exist in IIS" 448 | } 449 | 450 | # update the credentials 451 | if ($null -ne $Credentials) { 452 | $creds = Get-IISMCredentialDetails -Credentials $Credentials 453 | Invoke-IISMAppCommand -Arguments "set vdir '$($Name)' /userName:$($creds.username) /password:$($creds.password)" -NoParse | Out-Null 454 | } 455 | } -------------------------------------------------------------------------------- /src/Public/Ftp.ps1: -------------------------------------------------------------------------------- 1 | function Get-IISMFtpDirectoryAuthorization 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [Parameter(Mandatory=$true)] 6 | [string] 7 | $SiteName, 8 | 9 | [Parameter()] 10 | [string] 11 | $AppName = '/', 12 | 13 | [Parameter()] 14 | [string] 15 | $DirName 16 | ) 17 | 18 | # error if not ftp site 19 | if (!(Test-IISMSiteIsFtp -Name $SiteName)) { 20 | throw "Website '$($SiteName)' is not an FTP site" 21 | } 22 | 23 | $AppName = Add-IISMSlash -Value $AppName 24 | 25 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 26 | if (![string]::IsNullOrWhiteSpace($DirName)) { 27 | $Name = "$($Name)$($DirName)" 28 | } 29 | 30 | # error if the directory doesn't exist 31 | if (!(Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName)) { 32 | throw "Directory '$($Name)' does not exist in IIS" 33 | } 34 | 35 | return (Get-IISMFtpDirectoryAuthorizationInternal -Name $Name) 36 | } 37 | 38 | function Add-IISMFtpDirectoryAuthorization 39 | { 40 | [CmdletBinding()] 41 | param( 42 | [Parameter(Mandatory=$true)] 43 | [string] 44 | $SiteName, 45 | 46 | [Parameter()] 47 | [string] 48 | $AppName = '/', 49 | 50 | [Parameter()] 51 | [string] 52 | $DirName, 53 | 54 | [Parameter(Mandatory=$true)] 55 | [ValidateSet('Allow', 'Deny')] 56 | [string] 57 | $AccessType, 58 | 59 | [Parameter(Mandatory=$true)] 60 | [ValidateSet('Read', 'Write')] 61 | [string[]] 62 | $Permission, 63 | 64 | [Parameter()] 65 | [string[]] 66 | $User, 67 | 68 | [Parameter()] 69 | [string[]] 70 | $Role, 71 | 72 | [switch] 73 | $NoOutput 74 | ) 75 | 76 | # error if not ftp site 77 | if (!(Test-IISMSiteIsFtp -Name $SiteName)) { 78 | throw "Website '$($SiteName)' is not an FTP site" 79 | } 80 | 81 | $AppName = Add-IISMSlash -Value $AppName 82 | 83 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 84 | if (![string]::IsNullOrWhiteSpace($DirName)) { 85 | $Name = "$($Name)$($DirName)" 86 | } 87 | 88 | # error if the directory doesn't exist 89 | if (!(Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName)) { 90 | throw "Directory '$($Name)' does not exist in IIS" 91 | } 92 | 93 | # skip if it already has the auth 94 | $current = (Get-IISMFtpDirectoryAuthorizationInternal -Name $Name).Rules 95 | $check = ($current | Where-Object { 96 | ($_.AccessType -ieq $AccessType) -and 97 | ($_.Users -join ',') -ieq ($User -join ',') -and 98 | ($_.Roles -join ',') -ieq ($Role -join ',') -and 99 | ($_.Permissions -join ',') -ieq ($Permission -join ',') 100 | }) 101 | 102 | if ($null -ne $check) { 103 | return 104 | } 105 | 106 | # add the auth 107 | $auth = Get-IISMFtpAuthorizationCommandString -AccessType $AccessType -Permission $Permission -User $User -Role $Role 108 | Invoke-IISMAppCommand -Arguments "set config '$($Name)' /section:system.ftpServer/security/authorization /+`"$($auth)`" /commit:apphost" -NoParse | Out-Null 109 | 110 | if (!$NoOutput) { 111 | return (Get-IISMFtpDirectoryAuthorization -SiteName $SiteName -AppName $AppName -DirName $DirName) 112 | } 113 | } 114 | 115 | function Remove-IISMFtpDirectoryAuthorization 116 | { 117 | [CmdletBinding()] 118 | param( 119 | [Parameter(Mandatory=$true)] 120 | [string] 121 | $SiteName, 122 | 123 | [Parameter()] 124 | [string] 125 | $AppName = '/', 126 | 127 | [Parameter()] 128 | [string] 129 | $DirName, 130 | 131 | [Parameter(Mandatory=$true)] 132 | [ValidateSet('Allow', 'Deny')] 133 | [string] 134 | $AccessType, 135 | 136 | [Parameter(Mandatory=$true)] 137 | [ValidateSet('Read', 'Write')] 138 | [string[]] 139 | $Permission, 140 | 141 | [Parameter()] 142 | [string[]] 143 | $User, 144 | 145 | [Parameter()] 146 | [string[]] 147 | $Role, 148 | 149 | [switch] 150 | $NoOutput 151 | ) 152 | 153 | # error if not ftp site 154 | if (!(Test-IISMSiteIsFtp -Name $SiteName)) { 155 | throw "Website '$($SiteName)' is not an FTP site" 156 | } 157 | 158 | $AppName = Add-IISMSlash -Value $AppName 159 | 160 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 161 | if (![string]::IsNullOrWhiteSpace($DirName)) { 162 | $Name = "$($Name)$($DirName)" 163 | } 164 | 165 | # error if the directory doesn't exist 166 | if (!(Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName)) { 167 | throw "Directory '$($Name)' does not exist in IIS" 168 | } 169 | 170 | # skip if it doesnt have the auth 171 | $current = (Get-IISMFtpDirectoryAuthorizationInternal -Name $Name).Rules 172 | $check = ($current | Where-Object { 173 | ($_.AccessType -ieq $AccessType) -and 174 | ($_.Users -join ',') -ieq ($User -join ',') -and 175 | ($_.Roles -join ',') -ieq ($Role -join ',') -and 176 | ($_.Permissions -join ',') -ieq ($Permission -join ',') 177 | }) 178 | 179 | if ($null -eq $check) { 180 | return 181 | } 182 | 183 | # remove the auth 184 | $auth = Get-IISMFtpAuthorizationCommandString -AccessType $AccessType -Permission $Permission -User $User -Role $Role 185 | Invoke-IISMAppCommand -Arguments "set config '$($Name)' /section:system.ftpServer/security/authorization /-`"$($auth)`" /commit:apphost" -NoParse | Out-Null 186 | 187 | if (!$NoOutput) { 188 | return (Get-IISMFtpDirectoryAuthorization -SiteName $SiteName -AppName $AppName -DirName $DirName) 189 | } 190 | } 191 | 192 | function Get-IISMFtpDirectoryIPSecurity 193 | { 194 | [CmdletBinding()] 195 | param( 196 | [Parameter(Mandatory=$true)] 197 | [string] 198 | $SiteName, 199 | 200 | [Parameter()] 201 | [string] 202 | $AppName = '/', 203 | 204 | [Parameter()] 205 | [string] 206 | $DirName 207 | ) 208 | 209 | # error if not ftp site 210 | if (!(Test-IISMSiteIsFtp -Name $SiteName)) { 211 | throw "Website '$($SiteName)' is not an FTP site" 212 | } 213 | 214 | $AppName = Add-IISMSlash -Value $AppName 215 | 216 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 217 | if (![string]::IsNullOrWhiteSpace($DirName)) { 218 | $Name = "$($Name)$($DirName)" 219 | } 220 | 221 | # error if the directory doesn't exist 222 | if (!(Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName)) { 223 | throw "Directory '$($Name)' does not exist in IIS" 224 | } 225 | 226 | return (Get-IISMFtpDirectoryIPSecurityInternal -Name $Name) 227 | } 228 | 229 | function Add-IISMFtpDirectoryIPSecurity 230 | { 231 | [CmdletBinding()] 232 | param( 233 | [Parameter(Mandatory=$true)] 234 | [string] 235 | $SiteName, 236 | 237 | [Parameter()] 238 | [string] 239 | $AppName = '/', 240 | 241 | [Parameter()] 242 | [string] 243 | $DirName, 244 | 245 | [Parameter(Mandatory=$true)] 246 | [ValidateSet('Allow', 'Deny')] 247 | [string] 248 | $AccessType, 249 | 250 | [Parameter(Mandatory=$true)] 251 | [string] 252 | $IPAddress, 253 | 254 | [Parameter()] 255 | [ValidateNotNullOrEmpty()] 256 | [string] 257 | $SubnetMask = '255.255.255.255', 258 | 259 | [switch] 260 | $NoOutput 261 | ) 262 | 263 | # error if not ftp site 264 | if (!(Test-IISMSiteIsFtp -Name $SiteName)) { 265 | throw "Website '$($SiteName)' is not an FTP site" 266 | } 267 | 268 | $AppName = Add-IISMSlash -Value $AppName 269 | 270 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 271 | if (![string]::IsNullOrWhiteSpace($DirName)) { 272 | $Name = "$($Name)$($DirName)" 273 | } 274 | 275 | # error if the directory doesn't exist 276 | if (!(Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName)) { 277 | throw "Directory '$($Name)' does not exist in IIS" 278 | } 279 | 280 | # skip if it already has the auth 281 | $current = (Get-IISMFtpDirectoryIPSecurityInternal -Name $Name).Rules 282 | $check = ($current | Where-Object { 283 | ($_.AccessType -ieq $AccessType) -and 284 | ($_.IPAddress -ieq $IPAddress) -and 285 | ($_.SubnetMask -ieq $SubnetMask) 286 | }) 287 | 288 | if ($null -ne $check) { 289 | Write-Verbose "IP Security already exists" 290 | return 291 | } 292 | 293 | # add the auth 294 | $auth = Get-IISMFtpIPSecurityCommandString -AccessType $AccessType -IPAddress $IPAddress -SubnetMask $SubnetMask 295 | Invoke-IISMAppCommand -Arguments "set config '$($Name)' /section:system.ftpServer/security/ipSecurity /+`"$($auth)`" /commit:apphost" -NoParse | Out-Null 296 | 297 | if (!$NoOutput) { 298 | return (Get-IISMFtpDirectoryIPSecurity -SiteName $SiteName -AppName $AppName -DirName $DirName) 299 | } 300 | } 301 | 302 | function Remove-IISMFtpDirectoryIPSecurity 303 | { 304 | [CmdletBinding()] 305 | param( 306 | [Parameter(Mandatory=$true)] 307 | [string] 308 | $SiteName, 309 | 310 | [Parameter()] 311 | [string] 312 | $AppName = '/', 313 | 314 | [Parameter()] 315 | [string] 316 | $DirName, 317 | 318 | [Parameter(Mandatory=$true)] 319 | [ValidateSet('Allow', 'Deny')] 320 | [string] 321 | $AccessType, 322 | 323 | [Parameter(Mandatory=$true)] 324 | [string] 325 | $IPAddress, 326 | 327 | [Parameter()] 328 | [ValidateNotNullOrEmpty()] 329 | [string] 330 | $SubnetMask = '255.255.255.255', 331 | 332 | [switch] 333 | $NoOutput 334 | ) 335 | 336 | # error if not ftp site 337 | if (!(Test-IISMSiteIsFtp -Name $SiteName)) { 338 | throw "Website '$($SiteName)' is not an FTP site" 339 | } 340 | 341 | $AppName = Add-IISMSlash -Value $AppName 342 | 343 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 344 | if (![string]::IsNullOrWhiteSpace($DirName)) { 345 | $Name = "$($Name)$($DirName)" 346 | } 347 | 348 | # error if the directory doesn't exist 349 | if (!(Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName)) { 350 | throw "Directory '$($Name)' does not exist in IIS" 351 | } 352 | 353 | # skip if it doesnt have the auth 354 | $current = (Get-IISMFtpDirectoryIPSecurityInternal -Name $Name).Rules 355 | $check = ($current | Where-Object { 356 | ($_.AccessType -ieq $AccessType) -and 357 | ($_.IPAddress -ieq $IPAddress) -and 358 | ($_.SubnetMask -ieq $SubnetMask) 359 | }) 360 | 361 | if ($null -eq $check) { 362 | Write-Verbose "IP Security rule not found" 363 | return 364 | } 365 | 366 | # remove the auth 367 | $auth = Get-IISMFtpIPSecurityCommandString -AccessType $AccessType -IPAddress $IPAddress -SubnetMask $SubnetMask 368 | Invoke-IISMAppCommand -Arguments "set config '$($Name)' /section:system.ftpServer/security/ipSecurity /-`"$($auth)`" /commit:apphost" -NoParse | Out-Null 369 | 370 | if (!$NoOutput) { 371 | return (Get-IISMFtpDirectoryIPSecurity -SiteName $SiteName -AppName $AppName -DirName $DirName) 372 | } 373 | } 374 | 375 | function Set-IISMFtpDirectoryIPSecurityUnlisted 376 | { 377 | [CmdletBinding()] 378 | param( 379 | [Parameter(Mandatory=$true)] 380 | [string] 381 | $SiteName, 382 | 383 | [Parameter()] 384 | [string] 385 | $AppName = '/', 386 | 387 | [Parameter()] 388 | [string] 389 | $DirName, 390 | 391 | [Parameter(Mandatory=$true)] 392 | [ValidateSet('Allow', 'Deny')] 393 | [string] 394 | $AccessType 395 | ) 396 | 397 | # error if not ftp site 398 | if (!(Test-IISMSiteIsFtp -Name $SiteName)) { 399 | throw "Website '$($SiteName)' is not an FTP site" 400 | } 401 | 402 | $AppName = Add-IISMSlash -Value $AppName 403 | 404 | $Name = Add-IISMSlash -Value "$($SiteName)$($AppName)" -Append 405 | if (![string]::IsNullOrWhiteSpace($DirName)) { 406 | $Name = "$($Name)$($DirName)" 407 | } 408 | 409 | # error if the directory doesn't exist 410 | if (!(Test-IISMDirectory -SiteName $SiteName -AppName $AppName -DirName $DirName)) { 411 | throw "Directory '$($Name)' does not exist in IIS" 412 | } 413 | 414 | # set unlisted type 415 | $allow = ($AccessType -ieq 'Allow') 416 | Invoke-IISMAppCommand -Arguments "set config '$($Name)' /section:system.ftpServer/security/ipSecurity /allowUnlisted:'$($allow)' /commit:apphost" -NoParse | Out-Null 417 | } 418 | 419 | function Get-IISMFtpServerCustomAuthenticationProvider 420 | { 421 | [CmdletBinding()] 422 | param( 423 | [Parameter()] 424 | [string] 425 | $Name 426 | ) 427 | 428 | $result = Invoke-IISMAppCommand -Arguments 'list config /section:system.ftpServer/providerDefinitions' -NoError 429 | 430 | $providers = @(foreach ($provider in $result.CONFIG.'system.ftpServer-providerDefinitions'.add) { 431 | if (![string]::IsNullOrWhiteSpace($Name) -and ($provider.name -ine $Name)) { 432 | continue 433 | } 434 | 435 | @{ 436 | Name = $provider.name 437 | Type = $provider.type 438 | ClassId = $provider.clsid 439 | } 440 | }) 441 | 442 | return $providers 443 | } 444 | 445 | function Register-IISMFtpServerCustomAuthenticationProvider 446 | { 447 | [CmdletBinding()] 448 | param( 449 | [Parameter(Mandatory=$true)] 450 | [string] 451 | $Name, 452 | 453 | [Parameter(Mandatory=$true, ParameterSetName='ClassId')] 454 | [string] 455 | $ClassId, 456 | 457 | [Parameter(Mandatory=$true, ParameterSetName='Type')] 458 | [string] 459 | $Type 460 | ) 461 | 462 | # first, remove it, in case the details are different 463 | Unregister-IISMFtpServerCustomAuthenticationProvider -Name $Name 464 | 465 | # build the command for the auth type 466 | switch ($PSCmdlet.ParameterSetName) { 467 | 'ClassId' { 468 | $auth = "[name='$($Name)',clsid='$($ClassId)']" 469 | } 470 | 471 | 'Type' { 472 | $auth = "[name='$($Name)',type='$($Type)']" 473 | } 474 | } 475 | 476 | # run the command 477 | Invoke-IISMAppCommand -Arguments "set config /section:system.ftpServer/providerDefinitions /+`"$($auth)`"" -NoParse | Out-Null 478 | } 479 | 480 | function Unregister-IISMFtpServerCustomAuthenticationProvider 481 | { 482 | [CmdletBinding()] 483 | param( 484 | [Parameter(Mandatory=$true)] 485 | [string] 486 | $Name 487 | ) 488 | 489 | # do nothing if it doesn't exist 490 | $auth = Get-IISMFtpServerCustomAuthenticationProvider -Name $Name 491 | if (($null -eq $auth) -or ($auth.Length -eq 0)) { 492 | return 493 | } 494 | 495 | # build the command 496 | $auth = "[name='$($Name)']" 497 | 498 | # run the command 499 | Invoke-IISMAppCommand -Arguments "set config /section:system.ftpServer/providerDefinitions /-`"$($auth)`"" -NoParse | Out-Null 500 | } 501 | 502 | function Get-IISMFtpServerCustomAuthentication 503 | { 504 | [CmdletBinding()] 505 | param( 506 | [Parameter()] 507 | [string] 508 | $ProviderName 509 | ) 510 | 511 | $result = Invoke-IISMAppCommand -Arguments "list config /section:sites" -NoError 512 | $providers = $result.CONFIG.'system.applicationHost-sites'.siteDefaults.ftpServer.security.authentication.customAuthentication.providers.add 513 | 514 | if (($null -eq $providers) -or ($providers.Length -eq 0)) { 515 | return $null 516 | } 517 | 518 | $_providers = @(foreach ($provider in $providers) { 519 | @{ 520 | Name = $provider.name 521 | Enabled = ($provider.enabled -ieq 'true') 522 | } 523 | }) 524 | 525 | if ([string]::IsNullOrWhiteSpace($ProviderName)) { 526 | return $_providers 527 | } 528 | 529 | return ($_providers | Where-Object { $_.Name -ieq $ProviderName }) 530 | } 531 | 532 | function Add-IISMFtpServerCustomAuthentication 533 | { 534 | [CmdletBinding()] 535 | param( 536 | [Parameter(Mandatory=$true)] 537 | [string] 538 | $ProviderName, 539 | 540 | [switch] 541 | $Enable 542 | ) 543 | 544 | # remove it first 545 | Remove-IISMFtpServerCustomAuthentication -ProviderName $ProviderName 546 | 547 | # build the command 548 | $_args = "/+`"siteDefaults.ftpServer.security.authentication.customAuthentication.providers.[name='$($ProviderName)',enabled='$($Enable.IsPresent)']`"" 549 | 550 | # run the command 551 | Invoke-IISMAppCommand -Arguments "set config /section:sites $($_args)" -NoParse | Out-Null 552 | } 553 | 554 | function Remove-IISMFtpServerCustomAuthentication 555 | { 556 | [CmdletBinding()] 557 | param( 558 | [Parameter(Mandatory=$true)] 559 | [string] 560 | $ProviderName 561 | ) 562 | 563 | # do nothing if it doesn't exist 564 | $prov = Get-IISMFtpServerCustomAuthentication -ProviderName $ProviderName 565 | if (($null -eq $prov) -or ($prov.Length -eq 0)) { 566 | return 567 | } 568 | 569 | # build the command 570 | $_args = "/-`"siteDefaults.ftpServer.security.authentication.customAuthentication.providers.[name='$($ProviderName)']`"" 571 | 572 | # run the command 573 | Invoke-IISMAppCommand -Arguments "set config /section:sites $($_args)" -NoParse | Out-Null 574 | } 575 | 576 | function Set-IISMFtpSiteUserIsolation 577 | { 578 | [CmdletBinding()] 579 | param( 580 | [Parameter(Mandatory=$true)] 581 | [string] 582 | $Name, 583 | 584 | [Parameter(Mandatory=$true)] 585 | [ValidateSet('None', 'StartInUsersDirectory', 'IsolateAllDirectories', 'IsolateRootDirectoryOnly', 'ActiveDirectory')] 586 | [string] 587 | $Type, 588 | 589 | [Parameter()] 590 | [pscredential] 591 | $Credentials 592 | ) 593 | 594 | # error if the site doesn't exist 595 | if (!(Test-IISMSite -Name $Name)) { 596 | throw "Website '$($Name)' does not exist in IIS" 597 | } 598 | 599 | # error if the site isn't ftp 600 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 601 | throw "Website '$($Name)' is not an FTP site" 602 | } 603 | 604 | # set the isolation mode 605 | $_args = "/ftpServer.userIsolation.mode:$($Type)" 606 | 607 | if ($Type -ieq 'ActiveDirectory') { 608 | if ($null -eq $Credentials) { 609 | throw "No credentials supplied when attempting to set the '$($Name)' user isolation type to ActiveDirectory" 610 | } 611 | 612 | $creds = Get-IISMCredentialDetails -Credentials $Credentials 613 | $_args += " /ftpServer.userIsolation.activeDirectory.userName:$($creds.username) /ftpServer.userIsolation.activeDirectory.password:$($creds.password)" 614 | } 615 | 616 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' $($_args)" -NoParse | Out-Null 617 | } 618 | 619 | function Enable-IISMFtpSiteAuthentication 620 | { 621 | [CmdletBinding()] 622 | param( 623 | [Parameter(Mandatory=$true)] 624 | [string] 625 | $Name, 626 | 627 | [Parameter(ParameterSetName='Anonymous')] 628 | [switch] 629 | $Anonymous, 630 | 631 | [Parameter(ParameterSetName='Basic')] 632 | [switch] 633 | $Basic, 634 | 635 | [Parameter(ParameterSetName='ClientCertificate')] 636 | [switch] 637 | $ClientCertificate, 638 | 639 | [Parameter(ParameterSetName='Custom')] 640 | [switch] 641 | $Custom, 642 | 643 | [Parameter(ParameterSetName='Anonymous')] 644 | [pscredential] 645 | $Credentials, 646 | 647 | [Parameter(ParameterSetName='Anonymous')] 648 | [Parameter(ParameterSetName='Basic')] 649 | [string] 650 | $Domain, 651 | 652 | [Parameter(ParameterSetName='Anonymous')] 653 | [Parameter(ParameterSetName='Basic')] 654 | [string] 655 | $LogonMethod, 656 | 657 | [Parameter(Mandatory=$true, ParameterSetName='Custom')] 658 | [string] 659 | $ProviderName 660 | ) 661 | 662 | # error if the site doesn't exist 663 | if (!(Test-IISMSite -Name $Name)) { 664 | throw "Website '$($Name)' does not exist in IIS" 665 | } 666 | 667 | # error if the site isn't ftp 668 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 669 | throw "Website '$($Name)' is not an FTP site" 670 | } 671 | 672 | # build the command for the auth type 673 | $_args = [string]::Empty 674 | 675 | switch ($PSCmdlet.ParameterSetName) { 676 | 'Anonymous' { 677 | $_args = "/ftpServer.security.authentication.anonymousAuthentication.enabled:true" 678 | 679 | if (![string]::IsNullOrWhiteSpace($Domain)) { 680 | $_args += " /ftpServer.security.authentication.anonymousAuthentication.defaultLogonDomain:$($Domain)" 681 | } 682 | 683 | if (![string]::IsNullOrWhiteSpace($LogonMethod)) { 684 | $_args += " /ftpServer.security.authentication.anonymousAuthentication.logonMethod:$($LogonMethod)" 685 | } 686 | 687 | if ($null -ne $Credentials) { 688 | $info = Get-IISMCredentialDetails -Credentials $Credentials 689 | $_args += " /ftpServer.security.authentication.anonymousAuthentication.userName:$($info.Username) /ftpServer.security.authentication.anonymousAuthentication.password:$($info.Password)" 690 | } 691 | } 692 | 693 | 'Basic' { 694 | $_args = "/ftpServer.security.authentication.basicAuthentication.enabled:true" 695 | 696 | if (![string]::IsNullOrWhiteSpace($Domain)) { 697 | $_args += " /ftpServer.security.authentication.basicAuthentication.defaultLogonDomain:$($Domain)" 698 | } 699 | 700 | if (![string]::IsNullOrWhiteSpace($LogonMethod)) { 701 | $_args += " /ftpServer.security.authentication.basicAuthentication.logonMethod:$($LogonMethod)" 702 | } 703 | } 704 | 705 | 'ClientCertificate' { 706 | $_args = "/ftpServer.security.authentication.clientCertAuthentication.enabled:true" 707 | } 708 | 709 | 'Custom' { 710 | $_args = "/`"ftpServer.security.authentication.customAuthentication.providers.[name='$($ProviderName)'].enabled:true`"" 711 | } 712 | } 713 | 714 | # run the command 715 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' $($_args)" -NoParse | Out-Null 716 | } 717 | 718 | function Disable-IISMFtpSiteAuthentication 719 | { 720 | [CmdletBinding()] 721 | param( 722 | [Parameter(Mandatory=$true)] 723 | [string] 724 | $Name, 725 | 726 | [Parameter(ParameterSetName='Anonymous')] 727 | [switch] 728 | $Anonymous, 729 | 730 | [Parameter(ParameterSetName='Basic')] 731 | [switch] 732 | $Basic, 733 | 734 | [Parameter(ParameterSetName='ClientCertificate')] 735 | [switch] 736 | $ClientCertificate, 737 | 738 | [Parameter(ParameterSetName='Custom')] 739 | [switch] 740 | $Custom, 741 | 742 | [Parameter(Mandatory=$true, ParameterSetName='Custom')] 743 | [string] 744 | $ProviderName 745 | ) 746 | 747 | # error if the site doesn't exist 748 | if (!(Test-IISMSite -Name $Name)) { 749 | throw "Website '$($Name)' does not exist in IIS" 750 | } 751 | 752 | # error if the site isn't ftp 753 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 754 | throw "Website '$($Name)' is not an FTP site" 755 | } 756 | 757 | # build the command for the auth type 758 | $_args = [string]::Empty 759 | 760 | switch ($PSCmdlet.ParameterSetName) { 761 | 'Anonymous' { 762 | $_args = "/ftpServer.security.authentication.anonymousAuthentication.enabled:false" 763 | } 764 | 765 | 'Basic' { 766 | $_args = "/ftpServer.security.authentication.basicAuthentication.enabled:false" 767 | } 768 | 769 | 'ClientCertificate' { 770 | $_args = "/ftpServer.security.authentication.clientCertAuthentication.enabled:false" 771 | } 772 | 773 | 'Custom' { 774 | $_args = "/`"ftpServer.security.authentication.customAuthentication.providers.[name='$($ProviderName)'].enabled:false`"" 775 | } 776 | } 777 | 778 | # run the command 779 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' $($_args)" -NoParse | Out-Null 780 | } 781 | 782 | function Add-IISMFtpSiteCustomAuthentication 783 | { 784 | [CmdletBinding()] 785 | param( 786 | [Parameter(Mandatory=$true)] 787 | [string] 788 | $Name, 789 | 790 | [Parameter(Mandatory=$true)] 791 | [string] 792 | $ProviderName, 793 | 794 | [switch] 795 | $Enable 796 | ) 797 | 798 | # error if the site doesn't exist 799 | if (!(Test-IISMSite -Name $Name)) { 800 | throw "Website '$($Name)' does not exist in IIS" 801 | } 802 | 803 | # error if the site isn't ftp 804 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 805 | throw "Website '$($Name)' is not an FTP site" 806 | } 807 | 808 | # remove first, in case details are different 809 | Remove-IISMFtpSiteCustomAuthentication -Name $Name -ProviderName $ProviderName 810 | 811 | # either add it anew, or enable 812 | $_provider = ((Get-IISMSite -Name $Name).Ftp.Security.Authentication.Custom.Providers | Where-Object { $_.Name -ieq $ProviderName }) 813 | 814 | if ($null -eq $_provider) { 815 | # build the command 816 | $_args = "/+`"ftpServer.security.authentication.customAuthentication.providers.[name='$($ProviderName)',enabled='$($Enable.IsPresent)']`"" 817 | 818 | # run the command 819 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' $($_args)" -NoParse | Out-Null 820 | } 821 | else { 822 | Enable-IISMFtpSiteAuthentication -Custom -Name $Name -ProviderName $ProviderName 823 | } 824 | } 825 | 826 | function Remove-IISMFtpSiteCustomAuthentication 827 | { 828 | [CmdletBinding()] 829 | param( 830 | [Parameter(Mandatory=$true)] 831 | [string] 832 | $Name, 833 | 834 | [Parameter(Mandatory=$true)] 835 | [string] 836 | $ProviderName 837 | ) 838 | 839 | # error if the site doesn't exist 840 | if (!(Test-IISMSite -Name $Name)) { 841 | throw "Website '$($Name)' does not exist in IIS" 842 | } 843 | 844 | # error if the site isn't ftp 845 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 846 | throw "Website '$($Name)' is not an FTP site" 847 | } 848 | 849 | # build the command 850 | $_args = "/-`"ftpServer.security.authentication.customAuthentication.providers.[name='$($ProviderName)']`"" 851 | 852 | # run the command 853 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' $($_args)" -NoParse | Out-Null 854 | } 855 | 856 | function Set-IISMFtpSiteSslPolicy 857 | { 858 | [CmdletBinding()] 859 | param( 860 | [Parameter(Mandatory=$true)] 861 | [string] 862 | $Name, 863 | 864 | [Parameter(Mandatory=$true, ParameterSetName='Certificate')] 865 | [string] 866 | $CertificateName, 867 | 868 | [Parameter(Mandatory=$true, ParameterSetName='Thumbprint')] 869 | [string] 870 | $Thumbprint, 871 | 872 | [Parameter(Mandatory=$true)] 873 | [ValidateSet('Allow', 'Require')] 874 | [string] 875 | $Policy, 876 | 877 | [switch] 878 | $Use128Bit 879 | ) 880 | 881 | # if cert name, get thumbprint 882 | if ($PSCmdlet.ParameterSetName -ieq 'Certificate') { 883 | $Thumbprint = Get-IISMCertificateThumbprint -CertificateName $CertificateName 884 | } 885 | 886 | # error if no thumbprint 887 | if ([string]::IsNullOrWhiteSpace($Thumbprint)) { 888 | throw "A valid Certificate Name or Thumbprint is required when configuring FTP SSL for '$($Name)'" 889 | } 890 | 891 | # build the command 892 | $_args = "/ftpServer.security.ssl.serverCertHash:$($Thumbprint) /ftpServer.security.ssl.serverCertStoreName:My" 893 | $_args += " /ftpServer.security.ssl.ssl128:$($Use128Bit.IsPresent)" 894 | $_args += " /ftpServer.security.ssl.controlChannelPolicy:Ssl$($Policy) /ftpServer.security.ssl.dataChannelPolicy:Ssl$($Policy)" 895 | 896 | # run the command 897 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' $($_args)" -NoParse | Out-Null 898 | } 899 | 900 | function Get-IISMFtpSiteLogging 901 | { 902 | [CmdletBinding(DefaultParameterSetName='Default')] 903 | param ( 904 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 905 | [string] 906 | $Name, 907 | 908 | [Parameter(ParameterSetName='Default')] 909 | [switch] 910 | $Default 911 | ) 912 | 913 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 914 | 'site' { 915 | $logFields = Get-IISMFtpSiteLogFields -Name $Name 916 | $logPath = Get-IISMFtpSiteLogPath -Name $Name 917 | $logPeriod = Get-IISMFtpSiteLogPeriod -Name $Name 918 | } 919 | 920 | default { 921 | $logFields = Get-IISMFtpSiteLogFields -Default 922 | $logPath = Get-IISMFtpSiteLogPath -Default 923 | $logPeriod = Get-IISMFtpSiteLogPeriod -Default 924 | } 925 | } 926 | 927 | return (ConvertTo-IISMFtpSiteLoggingObject ` 928 | -Fields $logFields ` 929 | -Path $logPath ` 930 | -Period $logPeriod) 931 | } 932 | 933 | 934 | 935 | function Get-IISMFtpSiteLogPeriod 936 | { 937 | [CmdletBinding(DefaultParameterSetName='Default')] 938 | param ( 939 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 940 | [string] 941 | $Name, 942 | 943 | [Parameter(ParameterSetName='Default')] 944 | [switch] 945 | $Default 946 | ) 947 | 948 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 949 | 'site' { 950 | if (!(Test-IISMSite -Name $Name)) { 951 | throw "Website '$($Name)' does not exist in IIS" 952 | } 953 | 954 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 955 | throw "Website '$($Name)' is not an FTP site" 956 | } 957 | 958 | $result = Invoke-IISMAppCommand -Arguments "list site '$Name'" -NoError 959 | 960 | $period = $result.SITE.site.ftpServer.logFile.period 961 | if ([string]::IsNullOrWhiteSpace($period)) { 962 | $period = Get-IISMSiteLogPeriod -Default 963 | } 964 | } 965 | 966 | default { 967 | $result = Invoke-IISMAppCommand -Arguments "list config /section:sites" -NoError 968 | $period = $result.CONFIG.'system.applicationHost-sites'.siteDefaults.ftpServer.logFile.period 969 | $period = (Protect-IISMValue $period 'Daily') 970 | } 971 | } 972 | 973 | return $period 974 | } 975 | 976 | function Set-IISMFtpSiteLogPeriod 977 | { 978 | [CmdletBinding(DefaultParameterSetName='Default')] 979 | param ( 980 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 981 | [string] 982 | $Name, 983 | 984 | [Parameter(Mandatory=$true)] 985 | [ValidateSet('Hourly', 'Daily', 'Weekly', 'Monthly')] 986 | [string] 987 | $Period, 988 | 989 | [Parameter(ParameterSetName='Default')] 990 | [switch] 991 | $Default 992 | ) 993 | 994 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 995 | 'site' { 996 | if (!(Test-IISMSite -Name $Name)) { 997 | throw "Website '$($Name)' does not exist in IIS" 998 | } 999 | 1000 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 1001 | throw "Website '$($Name)' is not an FTP site" 1002 | } 1003 | 1004 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"[name='$($Name)'].ftpServer.logFile.period:$($Period)`"" -NoParse | Out-Null 1005 | } 1006 | 1007 | default { 1008 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"siteDefaults.ftpServer.logFile.period:$($Period)`"" -NoParse | Out-Null 1009 | } 1010 | } 1011 | } 1012 | 1013 | function Get-IISMFtpSiteLogPath 1014 | { 1015 | [CmdletBinding(DefaultParameterSetName='Default')] 1016 | param ( 1017 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 1018 | [string] 1019 | $Name, 1020 | 1021 | [Parameter(ParameterSetName='Default')] 1022 | [switch] 1023 | $Default 1024 | ) 1025 | 1026 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 1027 | 'site' { 1028 | if (!(Test-IISMSite -Name $Name)) { 1029 | throw "Website '$($Name)' does not exist in IIS" 1030 | } 1031 | 1032 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 1033 | throw "Website '$($Name)' is not an FTP site" 1034 | } 1035 | 1036 | $result = Invoke-IISMAppCommand -Arguments "list site '$Name'" -NoError 1037 | 1038 | $logpath = $result.SITE.site.ftpServer.logFile.directory 1039 | if ([string]::IsNullOrWhiteSpace($logpath)) { 1040 | $logpath = Get-IISMSiteLogPath -Default 1041 | } 1042 | 1043 | $logpath = (Join-Path $logpath "FTPSVC$($result.SITE.site.id)") 1044 | } 1045 | 1046 | default { 1047 | $result = Invoke-IISMAppCommand -Arguments "list config /section:sites" -NoError 1048 | $logpath = $result.CONFIG.'system.applicationHost-sites'.siteDefaults.ftpServer.logFile.directory 1049 | $logpath = (Protect-IISMValue $logpath (Get-IISMSiteDefaultLogPath)) 1050 | } 1051 | } 1052 | 1053 | return [System.Environment]::ExpandEnvironmentVariables($logpath) 1054 | } 1055 | 1056 | function Set-IISMFtpSiteLogPath 1057 | { 1058 | [CmdletBinding(DefaultParameterSetName='Default')] 1059 | param ( 1060 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 1061 | [string] 1062 | $Name, 1063 | 1064 | [Parameter(Mandatory=$true)] 1065 | [string] 1066 | $Path, 1067 | 1068 | [Parameter(ParameterSetName='Default')] 1069 | [switch] 1070 | $Default 1071 | ) 1072 | 1073 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 1074 | 'site' { 1075 | if (!(Test-IISMSite -Name $Name)) { 1076 | throw "Website '$($Name)' does not exist in IIS" 1077 | } 1078 | 1079 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 1080 | throw "Website '$($Name)' is not an FTP site" 1081 | } 1082 | 1083 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"[name='$($Name)'].ftpServer.logFile.directory:$($Path)`"" -NoParse | Out-Null 1084 | } 1085 | 1086 | default { 1087 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"siteDefaults.ftpServer.logFile.directory:$($Path)`"" -NoParse | Out-Null 1088 | } 1089 | } 1090 | } 1091 | 1092 | function Get-IISMFtpSiteLogFields 1093 | { 1094 | [CmdletBinding(DefaultParameterSetName='Default')] 1095 | param ( 1096 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 1097 | [string] 1098 | $Name, 1099 | 1100 | [Parameter(ParameterSetName='Default')] 1101 | [switch] 1102 | $Default 1103 | ) 1104 | 1105 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 1106 | 'site' { 1107 | if (!(Test-IISMSite -Name $Name)) { 1108 | throw "Website '$($Name)' does not exist in IIS" 1109 | } 1110 | 1111 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 1112 | throw "Website '$($Name)' is not an FTP site" 1113 | } 1114 | 1115 | $result = Invoke-IISMAppCommand -Arguments "list site '$Name'" -NoError 1116 | 1117 | $fields = $result.SITE.site.ftpServer.logFile.logExtFileFlags 1118 | if ([string]::IsNullOrWhiteSpace($fields)) { 1119 | $fields = Get-IISMFtpSiteLogFields -Default 1120 | } 1121 | } 1122 | 1123 | default { 1124 | $result = Invoke-IISMAppCommand -Arguments "list config /section:sites" -NoError 1125 | $fields = $result.CONFIG.'system.applicationHost-sites'.siteDefaults.ftpServer.logFile.logExtFileFlags 1126 | $fields = (Protect-IISMValue $fields (Get-IISMFtpSiteDefaultLogFields)) 1127 | } 1128 | } 1129 | 1130 | return ($fields -split ',').Trim() 1131 | } 1132 | 1133 | function Set-IISMFtpSiteLogFields 1134 | { 1135 | [CmdletBinding(DefaultParameterSetName='Default')] 1136 | param ( 1137 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 1138 | [string] 1139 | $Name, 1140 | 1141 | [Parameter(Mandatory=$true)] 1142 | [string[]] 1143 | $Fields, 1144 | 1145 | [Parameter(ParameterSetName='Default')] 1146 | [switch] 1147 | $Default 1148 | ) 1149 | 1150 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 1151 | 'site' { 1152 | if (!(Test-IISMSite -Name $Name)) { 1153 | throw "Website '$($Name)' does not exist in IIS" 1154 | } 1155 | 1156 | if (!(Test-IISMSiteIsFtp -Name $Name)) { 1157 | throw "Website '$($Name)' is not an FTP site" 1158 | } 1159 | 1160 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"[name='$($Name)'].ftpServer.logFile.logExtFileFlags:$($Fields -join ',')`"" -NoParse | Out-Null 1161 | } 1162 | 1163 | default { 1164 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"siteDefaults.ftpServer.logFile.logExtFileFlags:$($Fields -join ',')`"" -NoParse | Out-Null 1165 | } 1166 | } 1167 | } 1168 | 1169 | function Add-IISMFtpSiteLogField 1170 | { 1171 | [CmdletBinding(DefaultParameterSetName='Default')] 1172 | param ( 1173 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 1174 | [string] 1175 | $Name, 1176 | 1177 | [Parameter(Mandatory=$true)] 1178 | [string] 1179 | $Field, 1180 | 1181 | [Parameter(ParameterSetName='Default')] 1182 | [switch] 1183 | $Default 1184 | ) 1185 | 1186 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 1187 | 'site' { 1188 | $fields = Get-IISMFtpSiteLogFields -Name $Name 1189 | if ($fields -inotcontains $Field) { 1190 | $fields += $Field 1191 | } 1192 | 1193 | Set-IISMFtpSiteLogFields -Name $Name -Fields $fields 1194 | } 1195 | 1196 | default { 1197 | $fields = Get-IISMFtpSiteLogFields -Default 1198 | if ($fields -inotcontains $Field) { 1199 | $fields += $Field 1200 | } 1201 | 1202 | Set-IISMFtpSiteLogFields -Default -Fields $fields 1203 | } 1204 | } 1205 | } 1206 | 1207 | function Remove-IISMFtpSiteLogField 1208 | { 1209 | [CmdletBinding(DefaultParameterSetName='Default')] 1210 | param ( 1211 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 1212 | [string] 1213 | $Name, 1214 | 1215 | [Parameter(Mandatory=$true)] 1216 | [string] 1217 | $Field, 1218 | 1219 | [Parameter(ParameterSetName='Default')] 1220 | [switch] 1221 | $Default 1222 | ) 1223 | 1224 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 1225 | 'site' { 1226 | $fields = (Get-IISMFtpSiteLogFields -Name $Name | Where-Object { $_ -ine $Field }) 1227 | Set-IISMFtpSiteLogFields -Name $Name -Fields $fields 1228 | } 1229 | 1230 | default { 1231 | $fields = (Get-IISMFtpSiteLogFields -Default | Where-Object { $_ -ine $Field }) 1232 | Set-IISMFtpSiteLogFields -Default -Fields $fields 1233 | } 1234 | } 1235 | } 1236 | 1237 | function Clear-IISMFtpSiteLogFields 1238 | { 1239 | [CmdletBinding(DefaultParameterSetName='Default')] 1240 | param ( 1241 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 1242 | [string] 1243 | $Name, 1244 | 1245 | [Parameter(ParameterSetName='Default')] 1246 | [switch] 1247 | $Default 1248 | ) 1249 | 1250 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 1251 | 'site' { 1252 | Set-IISMFtpSiteLogFields -Name $Name -Fields @() 1253 | } 1254 | 1255 | default { 1256 | Set-IISMFtpSiteLogFields -Default -Fields @() 1257 | } 1258 | } 1259 | } 1260 | 1261 | function Test-IISMFtpSiteLogField 1262 | { 1263 | [CmdletBinding(DefaultParameterSetName='Default')] 1264 | param ( 1265 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 1266 | [string] 1267 | $Name, 1268 | 1269 | [Parameter(Mandatory=$true)] 1270 | [string] 1271 | $Field, 1272 | 1273 | [Parameter(ParameterSetName='Default')] 1274 | [switch] 1275 | $Default 1276 | ) 1277 | 1278 | # get current fields 1279 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 1280 | 'site' { 1281 | $fields = Get-IISMFtpSiteLogFields -Name $Name 1282 | } 1283 | 1284 | default { 1285 | $fields = Get-IISMFtpSiteLogFields -Default 1286 | } 1287 | } 1288 | 1289 | return ($fields -icontains $Field) 1290 | } -------------------------------------------------------------------------------- /src/Public/Logging.ps1: -------------------------------------------------------------------------------- 1 | function Get-IISMSiteLogging 2 | { 3 | [CmdletBinding(DefaultParameterSetName='Default')] 4 | param ( 5 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 6 | [string] 7 | $Name, 8 | 9 | [Parameter(ParameterSetName='Default')] 10 | [switch] 11 | $Default 12 | ) 13 | 14 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 15 | 'site' { 16 | $logFields = Get-IISMSiteLogFields -Name $Name 17 | $logCustomFields = Get-IISMSiteCustomLogFields -Name $Name 18 | $logFormat = Get-IISMSiteLogFormat -Name $Name 19 | $logPath = Get-IISMSiteLogPath -Name $Name 20 | $logPeriod = Get-IISMSiteLogPeriod -Name $Name 21 | } 22 | 23 | default { 24 | $logFields = Get-IISMSiteLogFields -Default 25 | $logCustomFields = Get-IISMSiteCustomLogFields -Default 26 | $logFormat = Get-IISMSiteLogFormat -Default 27 | $logPath = Get-IISMSiteLogPath -Default 28 | $logPeriod = Get-IISMSiteLogPeriod -Default 29 | } 30 | } 31 | 32 | return (ConvertTo-IISMSiteLoggingObject ` 33 | -Fields $logFields ` 34 | -CustomFields $logCustomFields ` 35 | -Format $logFormat ` 36 | -Path $logPath ` 37 | -Period $logPeriod) 38 | } 39 | 40 | function Get-IISMSiteLogFormat 41 | { 42 | [CmdletBinding(DefaultParameterSetName='Default')] 43 | param ( 44 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 45 | [string] 46 | $Name, 47 | 48 | [Parameter(ParameterSetName='Default')] 49 | [switch] 50 | $Default 51 | ) 52 | 53 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 54 | 'site' { 55 | if (!(Test-IISMSite -Name $Name)) { 56 | throw "Website '$($Name)' does not exist in IIS" 57 | } 58 | 59 | $result = Invoke-IISMAppCommand -Arguments "list site '$Name'" -NoError 60 | 61 | $format = $result.SITE.site.logFile.logFormat 62 | if ([string]::IsNullOrWhiteSpace($format)) { 63 | $format = Get-IISMSiteLogFormat -Default 64 | } 65 | } 66 | 67 | default { 68 | $result = Invoke-IISMAppCommand -Arguments "list config /section:sites" -NoError 69 | $format = $result.CONFIG.'system.applicationHost-sites'.siteDefaults.logFile.logFormat 70 | $format = (Protect-IISMValue $format 'W3C') 71 | } 72 | } 73 | 74 | return $format 75 | } 76 | 77 | function Get-IISMSiteLogPeriod 78 | { 79 | [CmdletBinding(DefaultParameterSetName='Default')] 80 | param ( 81 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 82 | [string] 83 | $Name, 84 | 85 | [Parameter(ParameterSetName='Default')] 86 | [switch] 87 | $Default 88 | ) 89 | 90 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 91 | 'site' { 92 | if (!(Test-IISMSite -Name $Name)) { 93 | throw "Website '$($Name)' does not exist in IIS" 94 | } 95 | 96 | $result = Invoke-IISMAppCommand -Arguments "list site '$Name'" -NoError 97 | 98 | $period = $result.SITE.site.logFile.period 99 | if ([string]::IsNullOrWhiteSpace($period)) { 100 | $period = Get-IISMSiteLogPeriod -Default 101 | } 102 | } 103 | 104 | default { 105 | $result = Invoke-IISMAppCommand -Arguments "list config /section:sites" -NoError 106 | $period = $result.CONFIG.'system.applicationHost-sites'.siteDefaults.logFile.period 107 | $period = (Protect-IISMValue $period 'Daily') 108 | } 109 | } 110 | 111 | return $period 112 | } 113 | 114 | function Set-IISMSiteLogPeriod 115 | { 116 | [CmdletBinding(DefaultParameterSetName='Default')] 117 | param ( 118 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 119 | [string] 120 | $Name, 121 | 122 | [Parameter(Mandatory=$true)] 123 | [ValidateSet('Hourly', 'Daily', 'Weekly', 'Monthly')] 124 | [string] 125 | $Period, 126 | 127 | [Parameter(ParameterSetName='Default')] 128 | [switch] 129 | $Default 130 | ) 131 | 132 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 133 | 'site' { 134 | if (!(Test-IISMSite -Name $Name)) { 135 | throw "Website '$($Name)' does not exist in IIS" 136 | } 137 | 138 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"[name='$($Name)'].logFile.period:$($Period)`"" -NoParse | Out-Null 139 | } 140 | 141 | default { 142 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"siteDefaults.logFile.period:$($Period)`"" -NoParse | Out-Null 143 | } 144 | } 145 | } 146 | 147 | function Get-IISMSiteLogPath 148 | { 149 | [CmdletBinding(DefaultParameterSetName='Default')] 150 | param ( 151 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 152 | [string] 153 | $Name, 154 | 155 | [Parameter(ParameterSetName='Default')] 156 | [switch] 157 | $Default 158 | ) 159 | 160 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 161 | 'site' { 162 | if (!(Test-IISMSite -Name $Name)) { 163 | throw "Website '$($Name)' does not exist in IIS" 164 | } 165 | 166 | $result = Invoke-IISMAppCommand -Arguments "list site '$Name'" -NoError 167 | 168 | $logpath = $result.SITE.site.logFile.directory 169 | if ([string]::IsNullOrWhiteSpace($logpath)) { 170 | $logpath = Get-IISMSiteLogPath -Default 171 | } 172 | 173 | $logpath = (Join-Path $logpath "W3SVC$($result.SITE.site.id)") 174 | } 175 | 176 | default { 177 | $result = Invoke-IISMAppCommand -Arguments "list config /section:sites" -NoError 178 | $logpath = $result.CONFIG.'system.applicationHost-sites'.siteDefaults.logFile.directory 179 | $logpath = (Protect-IISMValue $logpath (Get-IISMSiteDefaultLogPath)) 180 | } 181 | } 182 | 183 | return [System.Environment]::ExpandEnvironmentVariables($logpath) 184 | } 185 | 186 | function Set-IISMSiteLogPath 187 | { 188 | [CmdletBinding(DefaultParameterSetName='Default')] 189 | param ( 190 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 191 | [string] 192 | $Name, 193 | 194 | [Parameter(Mandatory=$true)] 195 | [string] 196 | $Path, 197 | 198 | [Parameter(ParameterSetName='Default')] 199 | [switch] 200 | $Default 201 | ) 202 | 203 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 204 | 'site' { 205 | if (!(Test-IISMSite -Name $Name)) { 206 | throw "Website '$($Name)' does not exist in IIS" 207 | } 208 | 209 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"[name='$($Name)'].logFile.directory:$($Path)`"" -NoParse | Out-Null 210 | } 211 | 212 | default { 213 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"siteDefaults.logFile.directory:$($Path)`"" -NoParse | Out-Null 214 | } 215 | } 216 | } 217 | 218 | function Get-IISMSiteLogFields 219 | { 220 | [CmdletBinding(DefaultParameterSetName='Default')] 221 | param ( 222 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 223 | [string] 224 | $Name, 225 | 226 | [Parameter(ParameterSetName='Default')] 227 | [switch] 228 | $Default 229 | ) 230 | 231 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 232 | 'site' { 233 | if (!(Test-IISMSite -Name $Name)) { 234 | throw "Website '$($Name)' does not exist in IIS" 235 | } 236 | 237 | $result = Invoke-IISMAppCommand -Arguments "list site '$Name'" -NoError 238 | 239 | $fields = $result.SITE.site.logFile.logExtFileFlags 240 | if ([string]::IsNullOrWhiteSpace($fields)) { 241 | $fields = Get-IISMSiteLogFields -Default 242 | } 243 | } 244 | 245 | default { 246 | $result = Invoke-IISMAppCommand -Arguments "list config /section:sites" -NoError 247 | $fields = $result.CONFIG.'system.applicationHost-sites'.siteDefaults.logFile.logExtFileFlags 248 | $fields = (Protect-IISMValue $fields (Get-IISMSiteDefaultLogFields)) 249 | } 250 | } 251 | 252 | return ($fields -split ',').Trim() 253 | } 254 | 255 | function Set-IISMSiteLogFields 256 | { 257 | [CmdletBinding(DefaultParameterSetName='Default')] 258 | param ( 259 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 260 | [string] 261 | $Name, 262 | 263 | [Parameter(Mandatory=$true)] 264 | [string[]] 265 | $Fields, 266 | 267 | [Parameter(ParameterSetName='Default')] 268 | [switch] 269 | $Default 270 | ) 271 | 272 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 273 | 'site' { 274 | if (!(Test-IISMSite -Name $Name)) { 275 | throw "Website '$($Name)' does not exist in IIS" 276 | } 277 | 278 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"[name='$($Name)'].logFile.logExtFileFlags:$($Fields -join ',')`"" -NoParse | Out-Null 279 | } 280 | 281 | default { 282 | Invoke-IISMAppCommand -Arguments "set config /section:sites /`"siteDefaults.logFile.logExtFileFlags:$($Fields -join ',')`"" -NoParse | Out-Null 283 | } 284 | } 285 | } 286 | 287 | function Add-IISMSiteLogField 288 | { 289 | [CmdletBinding(DefaultParameterSetName='Default')] 290 | param ( 291 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 292 | [string] 293 | $Name, 294 | 295 | [Parameter(Mandatory=$true)] 296 | [string] 297 | $Field, 298 | 299 | [Parameter(ParameterSetName='Default')] 300 | [switch] 301 | $Default 302 | ) 303 | 304 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 305 | 'site' { 306 | $fields = Get-IISMSiteLogFields -Name $Name 307 | if ($fields -inotcontains $Field) { 308 | $fields += $Field 309 | } 310 | 311 | Set-IISMSiteLogFields -Name $Name -Fields $fields 312 | } 313 | 314 | default { 315 | $fields = Get-IISMSiteLogFields -Default 316 | if ($fields -inotcontains $Field) { 317 | $fields += $Field 318 | } 319 | 320 | Set-IISMSiteLogFields -Default -Fields $fields 321 | } 322 | } 323 | } 324 | 325 | function Remove-IISMSiteLogField 326 | { 327 | [CmdletBinding(DefaultParameterSetName='Default')] 328 | param ( 329 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 330 | [string] 331 | $Name, 332 | 333 | [Parameter(Mandatory=$true)] 334 | [string] 335 | $Field, 336 | 337 | [Parameter(ParameterSetName='Default')] 338 | [switch] 339 | $Default 340 | ) 341 | 342 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 343 | 'site' { 344 | $fields = (Get-IISMSiteLogFields -Name $Name | Where-Object { $_ -ine $Field }) 345 | Set-IISMSiteLogFields -Name $Name -Fields $fields 346 | } 347 | 348 | default { 349 | $fields = (Get-IISMSiteLogFields -Default | Where-Object { $_ -ine $Field }) 350 | Set-IISMSiteLogFields -Default -Fields $fields 351 | } 352 | } 353 | } 354 | 355 | function Clear-IISMSiteLogFields 356 | { 357 | [CmdletBinding(DefaultParameterSetName='Default')] 358 | param ( 359 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 360 | [string] 361 | $Name, 362 | 363 | [Parameter(ParameterSetName='Default')] 364 | [switch] 365 | $Default 366 | ) 367 | 368 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 369 | 'site' { 370 | Set-IISMSiteLogFields -Name $Name -Fields @() 371 | } 372 | 373 | default { 374 | Set-IISMSiteLogFields -Default -Fields @() 375 | } 376 | } 377 | } 378 | 379 | function Test-IISMSiteLogField 380 | { 381 | [CmdletBinding(DefaultParameterSetName='Default')] 382 | param ( 383 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 384 | [string] 385 | $Name, 386 | 387 | [Parameter(Mandatory=$true)] 388 | [string] 389 | $Field, 390 | 391 | [Parameter(ParameterSetName='Default')] 392 | [switch] 393 | $Default 394 | ) 395 | 396 | # get current fields 397 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 398 | 'site' { 399 | $fields = Get-IISMSiteLogFields -Name $Name 400 | } 401 | 402 | default { 403 | $fields = Get-IISMSiteLogFields -Default 404 | } 405 | } 406 | 407 | return ($fields -icontains $Field) 408 | } 409 | 410 | function Get-IISMSiteCustomLogFields 411 | { 412 | [CmdletBinding(DefaultParameterSetName='Default')] 413 | param ( 414 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 415 | [string] 416 | $Name, 417 | 418 | [Parameter(ParameterSetName='Default')] 419 | [switch] 420 | $Default 421 | ) 422 | 423 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 424 | 'site' { 425 | if (!(Test-IISMSite -Name $Name)) { 426 | throw "Website '$($Name)' does not exist in IIS" 427 | } 428 | 429 | $result = Invoke-IISMAppCommand -Arguments "list site '$Name'" -NoError 430 | 431 | $fields = $result.SITE.site.logFile.customFields.add 432 | if ([string]::IsNullOrWhiteSpace($fields)) { 433 | $fields = Get-IISMSiteCustomLogFields -Default 434 | } 435 | } 436 | 437 | default { 438 | $result = Invoke-IISMAppCommand -Arguments "list config /section:sites" -NoError 439 | $fields = $result.CONFIG.'system.applicationHost-sites'.siteDefaults.logFile.customFields.add 440 | } 441 | } 442 | 443 | return (ConvertTo-IISMSiteCustomLogFieldObject -Fields $fields) 444 | } 445 | 446 | function Add-IISMSiteCustomLogField 447 | { 448 | [CmdletBinding(DefaultParameterSetName='Default')] 449 | param ( 450 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 451 | [string] 452 | $Name, 453 | 454 | [Parameter(Mandatory=$true)] 455 | [string] 456 | $Field, 457 | 458 | [Parameter(Mandatory=$true)] 459 | [ValidateSet('RequestHeader', 'ResponseHeader', 'ServerVariable')] 460 | [string] 461 | $Type, 462 | 463 | [Parameter()] 464 | [string] 465 | $Source, 466 | 467 | [Parameter(ParameterSetName='Default')] 468 | [switch] 469 | $Default 470 | ) 471 | 472 | # skip if it already exists 473 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 474 | 'site' { 475 | $exists = (Test-IISMSiteCustomLogField -Name $Name -Field $Field) 476 | } 477 | 478 | default { 479 | $exists = (Test-IISMSiteCustomLogField -Default -Field $Field) 480 | } 481 | } 482 | 483 | if ($exists) { 484 | return 485 | } 486 | 487 | # set source as field 488 | if ([string]::IsNullOrWhiteSpace($Source)) { 489 | $Source = $Field 490 | } 491 | 492 | # add the custom field 493 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 494 | 'site' { 495 | if (!(Test-IISMSite -Name $Name)) { 496 | throw "Website '$($Name)' does not exist in IIS" 497 | } 498 | 499 | Invoke-IISMAppCommand -Arguments "set config /section:sites /+`"[name='$($Name)'].logFile.customFields.[logFieldName='$($Field)',sourceName='$($Source)',sourceType='$($Type)']`"" -NoParse | Out-Null 500 | } 501 | 502 | default { 503 | Invoke-IISMAppCommand -Arguments "set config /section:sites /+`"siteDefaults.logFile.customFields.[logFieldName='$($Field)',sourceName='$($Source)',sourceType='$($Type)']`"" -NoParse | Out-Null 504 | } 505 | } 506 | } 507 | 508 | function Remove-IISMSiteCustomLogField 509 | { 510 | [CmdletBinding(DefaultParameterSetName='Default')] 511 | param ( 512 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 513 | [string] 514 | $Name, 515 | 516 | [Parameter(Mandatory=$true)] 517 | [string] 518 | $Field, 519 | 520 | [Parameter(ParameterSetName='Default')] 521 | [switch] 522 | $Default 523 | ) 524 | 525 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 526 | 'site' { 527 | if (!(Test-IISMSite -Name $Name)) { 528 | throw "Website '$($Name)' does not exist in IIS" 529 | } 530 | 531 | Invoke-IISMAppCommand -Arguments "set config /section:sites /-`"[name='$($Name)'].logFile.customFields.[logFieldName='$($Field)']`"" -NoParse | Out-Null 532 | } 533 | 534 | default { 535 | Invoke-IISMAppCommand -Arguments "set config /section:sites /-`"siteDefaults.logFile.customFields.[logFieldName='$($Field)']`"" -NoParse | Out-Null 536 | } 537 | } 538 | } 539 | 540 | function Clear-IISMSiteCustomLogFields 541 | { 542 | [CmdletBinding(DefaultParameterSetName='Default')] 543 | param ( 544 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 545 | [string] 546 | $Name, 547 | 548 | [Parameter(ParameterSetName='Default')] 549 | [switch] 550 | $Default 551 | ) 552 | 553 | # get current fields 554 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 555 | 'site' { 556 | $fields = Get-IISMSiteCustomLogFields -Name $Name 557 | } 558 | 559 | default { 560 | $fields = Get-IISMSiteCustomLogFields -Default 561 | } 562 | } 563 | 564 | # go through each one and remove them 565 | foreach ($field in $fields) { 566 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 567 | 'site' { 568 | Remove-IISMSiteCustomLogField -Name $Name -Field $field.Name 569 | } 570 | 571 | default { 572 | Remove-IISMSiteCustomLogField -Default -Field $field.Name 573 | } 574 | } 575 | } 576 | } 577 | 578 | function Test-IISMSiteCustomLogField 579 | { 580 | [CmdletBinding(DefaultParameterSetName='Default')] 581 | param ( 582 | [Parameter(Mandatory=$true, ParameterSetName='Site')] 583 | [string] 584 | $Name, 585 | 586 | [Parameter(Mandatory=$true)] 587 | [string] 588 | $Field, 589 | 590 | [Parameter(ParameterSetName='Default')] 591 | [switch] 592 | $Default 593 | ) 594 | 595 | # get current fields 596 | switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 597 | 'site' { 598 | $fields = Get-IISMSiteCustomLogFields -Name $Name 599 | } 600 | 601 | default { 602 | $fields = Get-IISMSiteCustomLogFields -Default 603 | } 604 | } 605 | 606 | return (@($fields | Where-Object { $_.Name -ieq $Field }).Length -eq 1) 607 | } -------------------------------------------------------------------------------- /src/Public/Misc.ps1: -------------------------------------------------------------------------------- 1 | function Reset-IISMServer 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [Parameter()] 6 | [string] 7 | $ComputerName 8 | ) 9 | 10 | Invoke-IISMResetCommand -Arguments "$($ComputerName)" | Out-Null 11 | } 12 | 13 | function Get-IISMCertificateThumbprint 14 | { 15 | [CmdletBinding()] 16 | param( 17 | [Parameter(Mandatory=$true)] 18 | [string] 19 | $CertificateName 20 | ) 21 | 22 | # if linux, fail 23 | if (Test-IsUnix) { 24 | throw 'This function cannot be used on *nix environments' 25 | } 26 | 27 | # add wildcards 28 | if (!$CertificateName.StartsWith('*')) { 29 | $CertificateName = "*$($CertificateName)" 30 | } 31 | 32 | if (!$CertificateName.EndsWith('*')) { 33 | $CertificateName = "$($CertificateName)*" 34 | } 35 | 36 | # get the cert from the store 37 | $cert = (Get-ChildItem 'Cert:\LocalMachine\My' | Where-Object { 38 | $_.Subject -ilike $CertificateName 39 | } | Select-Object -First 1) 40 | 41 | if ([string]::IsNullOrWhiteSpace($cert)) { 42 | return $null 43 | } 44 | 45 | return $cert.Thumbprint.ToString() 46 | } 47 | 48 | function New-IISMCredentials 49 | { 50 | [CmdletBinding()] 51 | [OutputType([pscredential])] 52 | param( 53 | [Parameter()] 54 | [string] 55 | $Username, 56 | 57 | [Parameter()] 58 | [string] 59 | $Password 60 | ) 61 | 62 | if ([string]::IsNullOrWhiteSpace($Username) -or [string]::IsNullOrWhiteSpace($Password)) { 63 | return $null 64 | } 65 | 66 | return (New-Object System.Management.Automation.PSCredential -ArgumentList $Username, (ConvertTo-SecureString -AsPlainText $Password -Force)) 67 | } 68 | 69 | function Invoke-IISMAppCommand 70 | { 71 | param ( 72 | [Parameter(Mandatory=$true)] 73 | [string] 74 | $Arguments, 75 | 76 | [switch] 77 | $NoParse, 78 | 79 | [switch] 80 | $NoError 81 | ) 82 | 83 | Write-Verbose $Arguments 84 | 85 | # run the command 86 | if ($NoParse) { 87 | $result = (Invoke-Expression -Command "$(Get-IISMAppCmdPath) $Arguments") 88 | } 89 | else { 90 | $result = (Invoke-Expression -Command "$(Get-IISMAppCmdPath) $Arguments /xml /config") 91 | } 92 | 93 | # check for errors 94 | if (($LASTEXITCODE -ne 0) -and !$NoError) { 95 | throw "Failed to run appcmd: $($result)" 96 | } 97 | 98 | # parse, if needed 99 | if (!$NoParse) { 100 | $result = ([xml]$result).appcmd 101 | } 102 | return $result 103 | } -------------------------------------------------------------------------------- /src/Public/Sites.ps1: -------------------------------------------------------------------------------- 1 | function Get-IISMSite 2 | { 3 | [CmdletBinding(DefaultParameterSetName='Path')] 4 | param ( 5 | [Parameter()] 6 | [string] 7 | $Name, 8 | 9 | [Parameter(ParameterSetName='Path')] 10 | [string] 11 | $PhysicalPath, 12 | 13 | [Parameter(ParameterSetName='Quick')] 14 | [switch] 15 | $Quick 16 | ) 17 | 18 | # get site(s) 19 | if (![string]::IsNullOrWhiteSpace($Name)) { 20 | $result = Invoke-IISMAppCommand -Arguments "list site '$($Name)'" -NoError 21 | } 22 | else { 23 | $result = Invoke-IISMAppCommand -Arguments 'list sites' -NoError 24 | } 25 | 26 | if ($null -eq $result.SITE) { 27 | return $null 28 | } 29 | 30 | # get list of IIS apps to map to sites 31 | $sites = ConvertTo-IISMSiteObject -Sites $result.SITE -Quick:$Quick 32 | 33 | # if we have a physical path, filter sites 34 | if (!$Quick -and ![string]::IsNullOrWhiteSpace($PhysicalPath)) { 35 | $sites = @($sites | Where-Object { 36 | $_.Apps | Where-Object { 37 | $_.Directories | Where-Object { 38 | $_.PhysicalPath -ieq $PhysicalPath 39 | } 40 | } 41 | }) 42 | 43 | foreach ($site in $sites) { 44 | $site.Apps = @($site.Apps | Where-Object { 45 | $_.Directories | Where-Object { 46 | $_.PhysicalPath -ieq $PhysicalPath 47 | } 48 | }) 49 | } 50 | } 51 | 52 | return $sites 53 | } 54 | 55 | function Get-IISMSites 56 | { 57 | [CmdletBinding()] 58 | param ( 59 | [Parameter()] 60 | [string[]] 61 | $Names, 62 | 63 | [switch] 64 | $Quick 65 | ) 66 | 67 | return @(foreach ($name in $Names) { Get-IISMSite -Name $name -Quick:$Quick }) 68 | } 69 | 70 | function Test-IISMSite 71 | { 72 | [CmdletBinding()] 73 | param ( 74 | [Parameter(Mandatory=$true)] 75 | [string] 76 | $Name 77 | ) 78 | 79 | $result = Invoke-IISMAppCommand -Arguments "list site '$($Name)'" -NoError 80 | return ($null -ne $result.SITE) 81 | } 82 | 83 | function Test-IISMSiteRunning 84 | { 85 | [CmdletBinding()] 86 | param ( 87 | [Parameter(Mandatory=$true)] 88 | [string] 89 | $Name 90 | ) 91 | 92 | return ((Get-IISMSite -Name $Name -Quick).State -ieq 'started') 93 | } 94 | 95 | function Stop-IISMSite 96 | { 97 | [CmdletBinding()] 98 | param ( 99 | [Parameter(Mandatory=$true)] 100 | [string] 101 | $Name 102 | ) 103 | 104 | if (Test-IISMSiteRunning -Name $Name) { 105 | Invoke-IISMAppCommand -Arguments "stop site '$($Name)'" -NoParse | Out-Null 106 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' /serverAutoStart:false" -NoParse | Out-Null 107 | } 108 | 109 | return (Get-IISMSite -Name $Name -Quick) 110 | } 111 | 112 | function Start-IISMSite 113 | { 114 | [CmdletBinding()] 115 | param ( 116 | [Parameter(Mandatory=$true)] 117 | [string] 118 | $Name 119 | ) 120 | 121 | if (!(Test-IISMSiteRunning -Name $Name)) { 122 | Invoke-IISMAppCommand -Arguments "start site '$($Name)'" -NoParse | Out-Null 123 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' /serverAutoStart:true" -NoParse | Out-Null 124 | } 125 | 126 | return (Get-IISMSite -Name $Name -Quick) 127 | } 128 | 129 | function Restart-IISMSite 130 | { 131 | [CmdletBinding()] 132 | param ( 133 | [Parameter(Mandatory=$true)] 134 | [string] 135 | $Name 136 | ) 137 | 138 | Stop-IISMSite -Name $Name | Out-Null 139 | Start-IISMSite -Name $Name | Out-Null 140 | return (Get-IISMSite -Name $Name -Quick) 141 | } 142 | 143 | function Get-IISMSiteBindings 144 | { 145 | [CmdletBinding()] 146 | param( 147 | [Parameter(Mandatory=$true)] 148 | [string] 149 | $Name 150 | ) 151 | 152 | # get site 153 | $result = Invoke-IISMAppCommand -Arguments "list site '$($Name)'" -NoError 154 | if ($null -eq $result.SITE) { 155 | return $null 156 | } 157 | 158 | # parse the list of binding 159 | return @(ConvertTo-IISMBindingObject -Site $result.SITE) 160 | } 161 | 162 | function Get-IISMSitePhysicalPath 163 | { 164 | [CmdletBinding()] 165 | param ( 166 | [Parameter(Mandatory=$true)] 167 | [string] 168 | $Name, 169 | 170 | [Parameter()] 171 | [string] 172 | $AppName = '/', 173 | 174 | [Parameter()] 175 | [string] 176 | $DirName 177 | ) 178 | 179 | $AppName = Add-IISMSlash -Value $AppName 180 | $DirName = Add-IISMSlash -Value $DirName 181 | 182 | $dirs = ((Get-IISMSite -Name $Name).Apps | Where-Object { 183 | $_.Path -ieq $AppName 184 | } | Select-Object -First 1).Directories 185 | 186 | return ($dirs | Where-Object { 187 | $_.Path -ieq $DirName 188 | } | Select-Object -First 1).PhysicalPath 189 | } 190 | 191 | function Get-IISMSiteAppPool 192 | { 193 | [CmdletBinding()] 194 | param ( 195 | [Parameter(Mandatory=$true)] 196 | [string] 197 | $Name, 198 | 199 | [Parameter()] 200 | [string] 201 | $AppName = '/' 202 | ) 203 | 204 | $AppName = Add-IISMSlash -Value $AppName 205 | 206 | return ((Get-IISMSite -Name $Name).Apps | Where-Object { 207 | $_.Path -ieq $AppName 208 | } | Select-Object -First 1).AppPool.Name 209 | } 210 | 211 | function Reset-IISMSiteAppPool 212 | { 213 | [CmdletBinding()] 214 | param ( 215 | [Parameter(Mandatory=$true)] 216 | [string] 217 | $Name 218 | ) 219 | 220 | (Get-IISMSite -Name $Name).Apps.AppPool.Name | Sort-Object -Unique | ForEach-Object { 221 | Reset-IISMAppPool -Name $_ | Out-Null 222 | } 223 | } 224 | 225 | function Edit-IISMSitePhysicalPath 226 | { 227 | [CmdletBinding()] 228 | param ( 229 | [Parameter(Mandatory=$true)] 230 | [string] 231 | $Name, 232 | 233 | [Parameter()] 234 | [string] 235 | $AppName = '/', 236 | 237 | [Parameter(Mandatory=$true)] 238 | [string] 239 | $PhysicalPath, 240 | 241 | [switch] 242 | $CreatePath 243 | ) 244 | 245 | $AppName = Add-IISMSlash -Value $AppName 246 | 247 | # error if the site doesn't exist 248 | if (!(Test-IISMSite -Name $Name)) { 249 | throw "Website '$($Name)' does not exist in IIS" 250 | } 251 | 252 | # get the site info 253 | $site = Get-IISMSite -Name $Name 254 | 255 | # error if this site doesn't have the supplied app 256 | $app = ($site.Apps | Where-Object { $_.Path -ieq $AppName }) 257 | if ($null -eq $app) { 258 | throw "The app '$($AppName)' does not exist against the website '$($Name)' in IIS" 259 | } 260 | 261 | # if create flag passed, make the path 262 | if ($CreatePath -and !(Test-Path $PhysicalPath)) { 263 | New-Item -Path $PhysicalPath -ItemType Directory -Force | Out-Null 264 | } 265 | 266 | # update the physical path 267 | Update-IISMDirectory -SiteName $Name -AppName $AppName -PhysicalPath $PhysicalPath | Out-Null 268 | 269 | # return the site 270 | return (Get-IISMSite -Name $Name) 271 | } 272 | 273 | function Remove-IISMSite 274 | { 275 | [CmdletBinding()] 276 | param ( 277 | [Parameter(Mandatory=$true)] 278 | [string] 279 | $Name 280 | ) 281 | 282 | if (Test-IISMSite -Name $Name) { 283 | # first remove all bindings - in an attempt to remove cert bindings 284 | Remove-IISMSiteBindings -Name $Name 285 | 286 | # then, remove the site and everything else 287 | Invoke-IISMAppCommand -Arguments "delete site '$($Name)'" -NoParse | Out-Null 288 | } 289 | 290 | return (Get-IISMSite) 291 | } 292 | 293 | function Test-IISMSiteBinding 294 | { 295 | [CmdletBinding()] 296 | param ( 297 | [Parameter(Mandatory=$true)] 298 | [string] 299 | $Name, 300 | 301 | [Parameter(Mandatory=$true)] 302 | [ValidateSet('ftp', 'http', 'https', 'msmq.formatname', 'net.msmq', 'net.pipe', 'net.tcp')] 303 | [string] 304 | $Protocol, 305 | 306 | [Parameter()] 307 | [int] 308 | $Port, 309 | 310 | [Parameter()] 311 | [string] 312 | $IPAddress, 313 | 314 | [Parameter()] 315 | [string] 316 | $Hostname 317 | ) 318 | 319 | # error if the site doesn't exist 320 | if (!(Test-IISMSite -Name $Name)) { 321 | throw "Website '$($Name)' does not exist in IIS" 322 | } 323 | 324 | # get the website bindings 325 | $bindings = Get-IISMSiteBindings -Name $Name 326 | foreach ($b in $bindings) { 327 | if ($b.Protocol -ieq $Protocol -and $b.Port -eq $Port -and $b.IPAddress -ieq $IPAddress -and $b.Hostname -ieq $Hostname) { 328 | return $true 329 | } 330 | } 331 | 332 | return $false 333 | } 334 | 335 | function Remove-IISMSiteBindings 336 | { 337 | [CmdletBinding()] 338 | param ( 339 | [Parameter(Mandatory=$true)] 340 | [string] 341 | $Name 342 | ) 343 | 344 | # error if the site doesn't exist 345 | if (!(Test-IISMSite -Name $Name)) { 346 | throw "Website '$($Name)' does not exist in IIS" 347 | } 348 | 349 | # remove all bindings 350 | @(Get-IISMSiteBindings -Name $Name) | ForEach-Object { 351 | $sslFlag = $_.SslFlags 352 | Remove-IISMSiteBinding -Name $Name -Protocol $_.Protocol -Port $_.Port -IPAddress $_.IPAddress -Hostname $_.Hostname -SslFlags:$sslFlag | Out-Null 353 | } 354 | } 355 | 356 | function Remove-IISMSiteBinding 357 | { 358 | [CmdletBinding()] 359 | param ( 360 | [Parameter(Mandatory=$true)] 361 | [string] 362 | $Name, 363 | 364 | [Parameter(Mandatory=$true)] 365 | [ValidateSet('ftp', 'http', 'https', 'msmq.formatname', 'net.msmq', 'net.pipe', 'net.tcp')] 366 | [string] 367 | $Protocol, 368 | 369 | [Parameter()] 370 | [int] 371 | $Port, 372 | 373 | [Parameter()] 374 | [string] 375 | $IPAddress, 376 | 377 | [Parameter()] 378 | [string] 379 | $Hostname, 380 | 381 | [switch] 382 | $SslFlags 383 | ) 384 | 385 | # error if the site doesn't exist 386 | if (!(Test-IISMSite -Name $Name)) { 387 | throw "Website '$($Name)' does not exist in IIS" 388 | } 389 | 390 | # do nothing if binding doesn't exist 391 | if (!(Test-IISMSiteBinding -Name $Name -Protocol $Protocol -Port $Port -IPAddress $IPAddress -Hostname $Hostname)) { 392 | return 393 | } 394 | 395 | # if https, attempt to unbind cert first 396 | if ($Protocol -ieq 'https') { 397 | Remove-IISMSiteBindingCertificate -Port $Port -IPAddress $IPAddress -Hostname $Hostname 398 | } 399 | 400 | $binding = Get-IISMBindingCommandString -Protocol $Protocol -Port $Port -IPAddress $IPAddress -Hostname $Hostname -SslFlags:$SslFlags 401 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' /-`"$($binding)`"" -NoParse | Out-Null 402 | return (Get-IISMSiteBindings -Name $Name) 403 | } 404 | 405 | function Remove-IISMSiteDefaultBinding 406 | { 407 | [CmdletBinding()] 408 | param ( 409 | [Parameter(Mandatory=$true)] 410 | [string] 411 | $Name 412 | ) 413 | 414 | return (Remove-IISMSiteBinding -Name $Name -Protocol http -Port 80 -IPAddress '*') 415 | } 416 | 417 | function Add-IISMSiteBinding 418 | { 419 | param ( 420 | [Parameter(Mandatory=$true)] 421 | [string] 422 | $Name, 423 | 424 | [Parameter(Mandatory=$true)] 425 | [ValidateSet('ftp', 'http', 'https', 'msmq.formatname', 'net.msmq', 'net.pipe', 'net.tcp')] 426 | [string] 427 | $Protocol, 428 | 429 | [Parameter()] 430 | [int] 431 | $Port, 432 | 433 | [Parameter()] 434 | [string] 435 | $IPAddress, 436 | 437 | [Parameter()] 438 | [string] 439 | $Hostname, 440 | 441 | [Parameter()] 442 | [string] 443 | $CertificateThumbprint, 444 | 445 | [switch] 446 | $SslFlags 447 | ) 448 | 449 | # error if the site doesn't exist 450 | if (!(Test-IISMSite -Name $Name)) { 451 | throw "Website '$($Name)' does not exist in IIS" 452 | } 453 | 454 | # attempt to remove the binding first, if it exists 455 | Remove-IISMSiteBinding -Name $Name -Protocol $Protocol -Port $Port -IPAddress $IPAddress -Hostname $Hostname | Out-Null 456 | 457 | # add the binding 458 | $binding = Get-IISMBindingCommandString -Protocol $Protocol -Port $Port -IPAddress $IPAddress -Hostname $Hostname -SslFlags:$SslFlags 459 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' /+`"$($binding)`"" -NoParse | Out-Null 460 | 461 | # if https, bind a certificate if thumbprint supplied 462 | if ($Protocol -ieq 'https' -and ![string]::IsNullOrWhiteSpace($CertificateThumbprint)) { 463 | Set-IISMSiteBindingCertificate -CertificateThumbprint $CertificateThumbprint -Port $Port -IPAddress $IPAddress -Hostname $Hostname 464 | } 465 | 466 | return (Get-IISMSiteBindings -Name $Name) 467 | } 468 | 469 | function Edit-IISMSiteAppPool 470 | { 471 | [CmdletBinding()] 472 | param ( 473 | [Parameter(Mandatory=$true)] 474 | [string] 475 | $Name, 476 | 477 | [Parameter()] 478 | [string] 479 | $AppName ='/', 480 | 481 | [Parameter(Mandatory=$true)] 482 | [string] 483 | $AppPoolName 484 | ) 485 | 486 | # error if the site doesn't exist 487 | if (!(Test-IISMSite -Name $Name)) { 488 | throw "Website '$($Name)' does not exist in IIS" 489 | } 490 | 491 | # error if the app doesn't exist 492 | $AppName = Add-IISMSlash -Value $AppName 493 | $FullAppName = "$($Name)$($AppName)" 494 | 495 | if (!(Test-IISMApp -SiteName $Name -Name $AppName)) { 496 | throw "Application '$($FullAppName)' does not exist in IIS" 497 | } 498 | 499 | # if the app-pool doesn't exist, create a default one 500 | if (!(Test-IISMAppPool -Name $AppPoolName)) { 501 | New-IISMAppPool -Name $AppPoolName | Out-Null 502 | } 503 | 504 | # bind the app-pool to the site's app 505 | Invoke-IISMAppCommand -Arguments "set app '$($FullAppName)' /applicationPool:'$($AppPoolName)'" -NoParse | Out-Null 506 | 507 | # return the site 508 | return (Get-IISMSite -Name $Name) 509 | } 510 | 511 | function New-IISMSite 512 | { 513 | [CmdletBinding()] 514 | param( 515 | [Parameter(Mandatory=$true)] 516 | [string] 517 | $Name, 518 | 519 | [Parameter()] 520 | [string] 521 | $AppPoolName = 'DefaultAppPool', 522 | 523 | [Parameter(Mandatory=$true)] 524 | [string] 525 | $PhysicalPath, 526 | 527 | [Parameter()] 528 | [pscredential] 529 | $Credentials, 530 | 531 | [switch] 532 | $CreatePath, 533 | 534 | [switch] 535 | $DisableAutoStart 536 | ) 537 | 538 | # error if site already exists 539 | if (Test-IISMSite -Name $Name) { 540 | throw "Website '$($Name)' already exists in IIS" 541 | } 542 | 543 | # if the app-pool doesn't exist, create a default one 544 | if (!(Test-IISMAppPool -Name $AppPoolName)) { 545 | New-IISMAppPool -Name $AppPoolName | Out-Null 546 | } 547 | 548 | # if create flag passed, make the path 549 | if ($CreatePath -and !(Test-Path $PhysicalPath)) { 550 | New-Item -Path $PhysicalPath -ItemType Directory -Force | Out-Null 551 | } 552 | 553 | # create the site in IIS 554 | $_args = "/name:'$($Name)' /physicalPath:'$($PhysicalPath)'" 555 | Invoke-IISMAppCommand -Arguments "add site $($_args)" -NoParse | Out-Null 556 | 557 | # set the physical vdir path creds 558 | if ($null -ne $Credentials) { 559 | Set-IISMDirectoryCredentials -SiteName $Name -Credentials $Credentials 560 | } 561 | 562 | # flag the site's auto start mode 563 | Invoke-IISMAppCommand -Arguments "set site '$($Name)' /serverAutoStart:$(!$DisableAutoStart)" -NoParse | Out-Null 564 | 565 | # bind the app-pool to the site's default app 566 | if ($AppPoolName -ine 'DefaultAppPool') { 567 | Edit-IISMSiteAppPool -Name $Name -AppName '/' -AppPoolName $AppPoolName | Out-Null 568 | } 569 | 570 | Wait-IISMBackgroundTask -ScriptBlock { Test-IISMSite -Name $Name } 571 | 572 | # return the site 573 | return (Get-IISMSite -Name $Name) 574 | } 575 | 576 | function Set-IISMSiteBindingCertificate 577 | { 578 | [CmdletBinding()] 579 | param ( 580 | [Parameter(Mandatory=$true)] 581 | [string] 582 | $CertificateThumbprint, 583 | 584 | [Parameter(Mandatory=$true)] 585 | [int] 586 | $Port, 587 | 588 | [Parameter()] 589 | [string] 590 | $IPAddress, 591 | 592 | [Parameter()] 593 | [string] 594 | $Hostname 595 | ) 596 | 597 | # error if no ip/hostname 598 | if ([string]::IsNullOrWhiteSpace($Hostname) -and [string]::IsNullOrWhiteSpace($IPAddress)) { 599 | throw "A Hostname or an IP Address is required when binding a certificate" 600 | } 601 | 602 | # error if already bound with cert 603 | if (Test-IISMSiteBindingCertificate -Port $Port -IPAddress $IPAddress -Hostname $Hostname) { 604 | throw "The binding '$($IPAddress):$($Port):$($Hostname)' is already bound with a certificate" 605 | } 606 | 607 | $appId = '{a3ba417c-dc1d-446b-95a5-a306ab26c1af}' 608 | 609 | # bind cert using hostname 610 | if (![string]::IsNullOrWhiteSpace($Hostname) -and $Hostname -ine '*') { 611 | $addr = "$($Hostname):$($Port)" 612 | $result = (Invoke-IISMNetshCommand -Arguments "http add sslcert hostnameport=$($addr) certhash=$($CertificateThumbprint) certstorename=MY appid='$($appId)'" -NoError) 613 | } 614 | 615 | # else, bind using IP address 616 | else { 617 | $addr = "$($IPAddress):$($Port)" 618 | $result = (Invoke-IISMNetshCommand -Arguments "http add sslcert ipport=$($addr) certhash=$($CertificateThumbprint) appid='$($appId)'" -NoError) 619 | } 620 | 621 | if ($LASTEXITCODE -ne 0 -or !$?) { 622 | throw "Failed to bind certificate against '$($addr)':`n$($result)" 623 | } 624 | } 625 | 626 | function Remove-IISMSiteBindingCertificate 627 | { 628 | [CmdletBinding()] 629 | param ( 630 | [Parameter(Mandatory=$true)] 631 | [int] 632 | $Port, 633 | 634 | [Parameter()] 635 | [string] 636 | $IPAddress, 637 | 638 | [Parameter()] 639 | [string] 640 | $Hostname 641 | ) 642 | 643 | # error if no ip/hostname 644 | if ([string]::IsNullOrWhiteSpace($Hostname) -and [string]::IsNullOrWhiteSpace($IPAddress)) { 645 | throw "A Hostname or an IP Address is required when removing a bound certificate" 646 | } 647 | 648 | # do nothing if not bound 649 | if (!(Test-IISMSiteBindingCertificate -Port $Port -IPAddress $IPAddress -Hostname $Hostname)) { 650 | return 651 | } 652 | 653 | # delete cert using hostname 654 | if (![string]::IsNullOrWhiteSpace($Hostname) -and $Hostname -ine '*') { 655 | $addr = "$($Hostname):$($Port)" 656 | $result = (Invoke-IISMNetshCommand -Arguments "http delete sslcert hostnameport=$($addr)" -NoError) 657 | } 658 | 659 | # else, delete using IP address 660 | else { 661 | $addr = "$($IPAddress):$($Port)" 662 | $result = (Invoke-IISMNetshCommand -Arguments "http delete sslcert ipport=$($addr)" -NoError) 663 | } 664 | 665 | if ($LASTEXITCODE -ne 0 -or !$?) { 666 | throw "Failed to delete certificate against '$($addr)':`n$($result)" 667 | } 668 | } 669 | 670 | function Test-IISMSiteBindingCertificate 671 | { 672 | [CmdletBinding()] 673 | param ( 674 | [Parameter(Mandatory=$true)] 675 | [int] 676 | $Port, 677 | 678 | [Parameter()] 679 | [string] 680 | $IPAddress, 681 | 682 | [Parameter()] 683 | [string] 684 | $Hostname 685 | ) 686 | 687 | return ($null -ne (Get-IISMSiteBindingCertificate -Port $Port -IPAddress $IPAddress -Hostname $Hostname)) 688 | } 689 | 690 | function Get-IISMSiteBindingCertificate 691 | { 692 | [CmdletBinding(DefaultParameterSetName='Port')] 693 | param( 694 | [Parameter(Mandatory=$true, ParameterSetName='Port')] 695 | [int] 696 | $Port, 697 | 698 | [Parameter(ParameterSetName='Port')] 699 | [string] 700 | $IPAddress, 701 | 702 | [Parameter(ParameterSetName='Port')] 703 | [string] 704 | $Hostname, 705 | 706 | [Parameter(Mandatory=$true, ParameterSetName='Thumbprint')] 707 | [string] 708 | $Thumbprint 709 | ) 710 | 711 | if ($PSCmdlet.ParameterSetName -ieq 'port') { 712 | # get netsh details by ip address 713 | $details = (Invoke-IISMNetshCommand -Arguments "http show sslcert ipport=$($IPAddress):$($Port)" -NoError) 714 | 715 | # if that threw an error, and we have a hostname, check that 716 | if ($LASTEXITCODE -ne 0 -and ![string]::IsNullOrWhiteSpace($Hostname) -and $Hostname -ine '*') { 717 | $details = (Invoke-IISMNetshCommand -Arguments "http show sslcert hostnameport=$($Hostname):$($Port)" -NoError) 718 | } 719 | 720 | # get the thumbprint from the output 721 | $Thumbprint = (($details -imatch 'Certificate Hash\s+:\s+([a-z0-9]+)') -split ':')[1] 722 | if (![string]::IsNullOrWhiteSpace($Thumbprint)) { 723 | $Thumbprint = $Thumbprint.Trim() 724 | } 725 | } 726 | 727 | # if no thumbprint, return null 728 | if ([string]::IsNullOrWhiteSpace($Thumbprint)) { 729 | return $null 730 | } 731 | 732 | # get cert subject if on windows 733 | if (!(Test-IsUnix)) { 734 | $subject = (Get-ChildItem "Cert:/LocalMachine/My/$($Thumbprint)").Subject 735 | } 736 | 737 | # return the cert details 738 | return @{ 739 | Thumbprint = $Thumbprint 740 | Subject = $subject 741 | } 742 | } 743 | 744 | function Test-IISMSiteIsFtp 745 | { 746 | [CmdletBinding()] 747 | param ( 748 | [Parameter(Mandatory=$true)] 749 | [string] 750 | $Name 751 | ) 752 | 753 | $bindings = @(Get-IISMSiteBindings -Name $Name) 754 | return ($bindings.Protocol -icontains 'ftp') 755 | } --------------------------------------------------------------------------------