The WebAdministration Module ships with a couple functions for working with virtual directories:
But, there are some glitches with them.
- New-WebVirtualDirectory doesn’t require PhysicalPath to be set, which can cause errors in IIS Manager. IIS runs fine, it’s just the manager that throws an error when parsing applicationHost.config.
- Remove-WebVirtualDirectory will always pop-up a windowed confirmation prompt if the virtual directory has files or folders below it. Deleting a virtual directory doesn’t cause any harm to the files, so it shouldn’t be appearing. The troubling part is there is no override to –Force or turn the confirmation off (-Confirm: $false).
A way to get around these problems is to write a wrapper class around the functions. Making the PhysicalPath property on New-WebVirtualDirectory is pretty easy to do, but the other one …
To prevent the confirmation prompt from popping up, the wrapper function can create an empty temporary directory, repoint the virtual directory to it, remove the virtual directory, and then remove the temporary directory.
This code below also wrapped the Get-WebVirtualDirectory because I wanted an API that took a Url as input and figure out how to use it.
Here’s a full list of the wrappers and helper functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
<# .SYNOPSIS Takes a url and breaks it into these parts: Ssl, SiteName, AppName, AppNames. .DESCRIPTION Takes a url and breaks it into these parts for a [PSObject]: Ssl - true/false - does the url request ssl SiteName - string - the dns host name AppName - string - the AppNames as a single string. It starts with '/'. AppNames - Array<string> - each folder name within the local path .PARAMETER Url The url to convert into it's UriPaths .EXAMPLE $uriPaths = ConvertTo-WebUriPaths "https://www.contoso.com/services" #> Function ConvertTo-WebUriPaths { Param ( [ Parameter ( Mandatory = $true )] [string] $Url ) $paths = @{ Ssl = $null ; SiteName = " "; AppNames = @(); AppName = ""; }; $uri = New-Object System.Uri $Url; $paths = New-PsType " UriPaths " Add-PsTypeField $paths " Ssl " ($uri.Scheme -eq " https ") Add-PsTypeField $paths " SiteName " $uri.Host Add-PsTypeField $paths " AppNames " $uri.LocalPath.Split(" / ", [StringSplitOptions]::RemoveEmptyEntries) Add-PsTypeField $paths " AppName " $uri.LocalPath # remove trailing slash, if exists if($paths.AppName) { $appNameLen = $paths.AppName.Length; if($paths.AppName[$appNameLen - 1] -eq " / ") { $paths.AppName = $paths.AppName.Substring(0, $appNameLen - 1); } } return $paths; } <# .SYNOPSIS Takes a UriPaths object (from ConvertTo-UriPaths) and turns it into and IIS:\Sites\XXXX string value. .PARAMETER UriPaths The UriPaths object from ConvertTo-WebUriPaths .EXAMPLE $iisPath = ConvertTo-WebIISPath $uriPaths .LINK ConvertTo-WebUriPaths #> Function ConvertTo-WebIISPath { Param ( [Parameter(Mandatory = $true)] [PSObject] $UriPaths ) $iisPath = " IIS:\Sites\ " + $UriPaths.SiteName; $UriPaths.AppNames |% { $iisPath += " \ " + $_ }; # alternateively, AppName could also be used return $iisPath; } <# .SYNOPSIS Using the given url to search the current server for the longest parent website/webapp path that matches the url. It will only return the parent website/app information. if the root website is given, then $null will be returned. The webapp's information from the IIS:\Sites protocol is returned. .PARAMETER Url The url to search on .EXAMPLE #> Function Get-WebParentAppByUrl { Param ( [Parameter(Mandatory = $true)] [string] $Url ) $uriPaths = ConvertTo-WebUriPaths -Url $Url $currentPath = " IIS:\Sites\{0} " -f $uriPaths.SiteName if((Test-Path $currentPath) -eq $false) { return $null } if($uriPaths.AppName -eq "" -or $uriPaths.AppName -eq " / ") { return $null} $webApp = Get-Item $currentPath if($uriPaths.AppNames -is [Array]) { for($i = 0; $i -lt $uriPaths.AppNames.Count - 1; $i++) { $currentPath += " \{0} " -f $uriPaths.AppNames[$i] if(Test-Path $currentPath) { $webApp = Get-Item $currentPath } } } return $webApp } <# .SYNOPSIS Get virtual directory information from a site/app. If the given Url is a site/app, this will search for all virtual directories at the same level as the given the path. If not a site/app, this will search for a virtual directory under the parent site/app. .PARAMETER Url The url to search at. .EXAMPLE #> Function Get-WebVirtualDirectoryWrapper { [OutputType([Microsoft.IIs.PowerShell.Framework.ConfigurationElement])] Param ( [Parameter(Mandatory = $true)] [string] $Url ) $uriPaths = ConvertTo-WebUriPaths -Url $Url # check if the url is a site/app $iisPath = ConvertTo-WebIISPath -UriPaths $uriPaths if(-not (Test-Path $iisPath)) { Write-Warning " IIS $env:COMPUTERNAME - No path could be found for '$Url' . No virtual directories could be looked up. " return $null } $node = Get-Item $iisPath if(@(" Application ", " Site ") -contains $node.ElementTagName) { # search for virtual directories below this level $vdirs = Get-WebVirtualDirectory -Site $uriPaths.SiteName -Application $uriPaths.AppName } else { # search the parent app for the given virtual directory name $parentApp = Get-WebParentAppByUrl $Url $vdir = $uriPaths.AppName.Substring($parentApp.path.Length) $appPath = $parentApp.path if(-not $appPath) { $appPath = " / " } $vdirs = Get-WebVirtualDirectory -Site $uripaths.SiteName -Application $appPath -Name $vdir } return $vdirs } <# .SYNOPSIS Set a virtual directory for a site/app. This will set the physical path for the given Url. .PARAMETER Url The url to turn into a virtual directory. .PARAMETER PhysicalPath The physical path on the server to attach to the virtual path. .PARAMETER Force Overwrites the current physical path if already set. .EXAMPLE # Create a new virtual directory $vdir = New-WebVirtualDirectoryWrapper ` -PhysicalPath " D:\AllContent\Data\admissions.{env}.sa.ucsb.edu " -ServerName " SA89 " #> Function New-WebVirtualDirectoryWrapper { [OutputType([Microsoft.IIs.PowerShell.Framework.ConfigurationElement])] Param ( [Parameter(Mandatory = $true)] [string] $Url, [Parameter(Mandatory = $true)] [string] $PhysicalPath, [switch] $Force ) $uriPaths = ConvertTo-WebUriPaths -Url $Url # parse the name of the virtual directory from the given url if($uriPaths.AppName -eq "" -or $uriPaths.AppName -eq " / ") { throw " IIS $env:COMPUTERNAME - No virtual path could be found in url '$Url' . A subpath needs to be defined within the url. " } $parentApp = Get-WebParentAppByUrl -Url $Url if($parentApp -eq $null) { throw " IIS $env:COMPUTERNAME - No parent application could be found for url '$Url' . No virtual directory could be added. " } $appPath = $parentApp.path if(-not $appPath) { $appPath = " / " } $vdirPath = $uriPaths.AppName.Substring($appPath.Length) # if the vdirPath is multiple levels deep, check that the root path exists if($vdirPath.Split(" / ", [StringSplitOptions]::RemoveEmptyEntries).Count -gt 1) { $i = $vdirPath.LastIndexOf(" / ") $rootSubLevel = $vdirPath.Substring(0,$i).Replace(" / "," \ ") $iisPath = " IIS:\Sites\{0}\{1} " -f $uriPaths.SiteName, $rootSubLevel if((Test-Path $iisPath) -eq $false) { throw " IIS $env:COMPUTERNAME - Part of the sub path for '$Url' could not be found. Please ensure the full base path exists in IIS. " } } Write-Warning " IIS $env:COMPUTERNAME - Creating a virtual directory for $Url to $PhysicalPath . " if($Force) { if($appPath -eq " / ") { # it adds an extra / if you set the applicationName to '/' $vdir = New-WebVirtualDirectory -Site $uriPaths.SiteName -Name $vdirPath -PhysicalPath $PhysicalPath -Force } else { $vdir = New-WebVirtualDirectory -Site $uriPaths.SiteName -Application $appPath -Name $vdirPath -PhysicalPath $PhysicalPath -Force } } else { if($appPath -eq " / ") { # it adds an extra / if you set the applicationName to '/' $vdir = New-WebVirtualDirectory -Site $uriPaths.SiteName -Name $vdirPath -PhysicalPath $PhysicalPath } else { $vdir = New-WebVirtualDirectory -Site $uriPaths.SiteName -Application $appPath -Name $vdirPath -PhysicalPath $PhysicalPath } } Write-Host " IIS $env:COMPUTERNAME - Created a virtual directory for $Url to $PhysicalPath . " return $vdir } <# .SYNOPSIS Removes a virtual directory from a site/app. It will only remove the virtual directory if the Url given matches up with a virtual directory. .PARAMETER Url The url to search at. .EXAMPLE #> Function Remove-WebVirtualDirectoryWrapper { Param ( [Parameter(Mandatory = $true)] [string] $Url ) $uriPaths = ConvertTo-WebUriPaths -Url $Url # parse the name of the virtual directory from the given url if($uriPaths.AppName -eq "" -or $uriPaths.AppName -eq " / ") { throw " IIS $env:COMPUTERNAME - No virtual path could be found in url '$Url' . A subpath needs to be defined within the url. " } $parentApp = Get-WebParentAppByUrl -Url $Url if($parentApp -eq $null) { throw " IIS $env:COMPUTERNAME - No parent application could be found for url '$Url' . No virtual directory could be added. " } # ensure the path is a virtual directory $iisPath = ConvertTo-WebIISPath -UriPaths $uriPaths if(-not (Test-Path $iisPath)) { throw " IIS $env:COMPUTERNAME - No path for $Url could be found in IIS. " } $node = Get-Item $iisPath if($node.ElementTagName -ne " VirtualDirectory ") { switch($node.GetType().FullName) { " System.IO.FileInfo " { $type = " File " } " System.IO.DirectoryInfo " { $type = " Directory " } " Microsoft.IIs.PowerShell.Framework.ConfigurationElement " { $type = $node.ElementTagName } } throw " IIS $env:COMPUTERNAME - The url '$Url' doesn 't match with a Virtual Directory. It is a $type." } $vdirPath = $uriPaths.AppName.Substring($parentApp.path.Length) # check if the virtual path has files or folders beneath it. An error will occur if there are. $iisVPath = ConvertTo-WebIISPath -UriPaths $uriPaths $childItems = Get-ChildItem $iisVPath if($childItems) { Write-Warning ("IIS $env:COMPUTERNAME - The virtual path at ' $Url ' has items beneth it. Due to a bug in " + ` " WebAdministration\Remove-WebVirtualDirectory this would force a windows pop-up dialog to get approval." + ` " To get around this, a temporary folder will be created and the current virtual directory will" + ` " be repointed to the new (empty) location before removal. After removal of the virtual directory" + ` " the temporary folder will also be removed. The domain account this process runs under will need" + ` " permissions to the temporary folder location to create and remove it.") $guid = [Guid]::NewGuid() $PhysicalPath = (Get-WebVirtualDirectoryWrapper -Url $Url).PhysicalPath $tempPath = Join-Path $PhysicalPath $guid Write-Warning "IIS $env:COMPUTERNAME - Creating temp directory ' $tempDir ' in order to remove a virtual directory." $tempDir = New-Item $tempPath -ItemType Directory Write-Host "IIS $env:COMPUTERNAME - Created temp directory ' $tempDir ' in order to remove a virtual directory." $void = New-WebVirtualDirectoryWrapper -Url $Url -PhysicalPath $tempPath -Force } $appPath = $parentApp.path if(-not $appPath) { $appPath = "/" } Write-Warning "IIS $env:COMPUTERNAME - Removing a virtual directory ' $vdirPath ' for ' $Url '." Remove-WebVirtualDirectory -Site $uriPaths.SiteName -Application $appPath -Name $vdirPath Write-Host "IIS $env:COMPUTERNAME - Removed a virtual directory ' $vdirPath ' for ' $Url '." if($tempDir) { Write-Warning "IIS $env:COMPUTERNAME - Removing temp directory ' $tempDir ' in order to remove a virtual directory." $void = Remove-Item $tempDir Write-Host "IIS $env:COMPUTERNAME - Removed temp directory ' $tempDir ' in order to remove a virtual directory." } } |
0 comments:
Post a Comment